home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Utilities / MView / meshop.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-30  |  111.1 KB  |  3,668 lines

  1. /*//////////////////////////////////////////////////////////////////////////////
  2. //
  3. // File: meshop.cpp
  4. //
  5. // Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
  6. //
  7. //
  8. //////////////////////////////////////////////////////////////////////////////*/
  9.  
  10. #include "mviewpch.h"
  11.  
  12. LRESULT CALLBACK 
  13. DlgProcOutput(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  14.  
  15. HRESULT SplitMesh
  16.         (
  17.             LPD3DXMESH  pMesh,              // ASSUMPTION:  *pMesh is attribute sorted & has a valid attribute table
  18.             DWORD       iAttrSplit,         // **ppMeshB gets the mesh comprising of this attribute range onward
  19.             DWORD*      rgiAdjacency, 
  20.             DWORD       optionsA, 
  21.             DWORD       optionsB, 
  22.             LPD3DXMESH* ppMeshA, 
  23.             LPD3DXMESH* ppMeshB
  24.         );
  25.  
  26. // used when searching a remaping for the new selected value
  27. DWORD FindDWORD
  28.     (
  29.     DWORD dwFind, 
  30.     DWORD *rgdwSrc, 
  31.     DWORD cDWords
  32.     )
  33. {
  34.     DWORD iDWord;
  35.     for (iDWord = 0; iDWord < cDWords; iDWord++)
  36.     {
  37.         if (rgdwSrc[iDWord] == dwFind)
  38.         {
  39.             return iDWord;
  40.         }
  41.     }
  42.  
  43.     return UNUSED32;
  44. }
  45. void 
  46. TrivialData::NormalizeNormals()
  47. {
  48.     HRESULT hr;
  49.     LPD3DXBUFFER pbufVertRemap = NULL;
  50.     CD3DXCrackDecl1 cd;
  51.     DWORD cVertices;
  52.     D3DXVECTOR3 *pvNormal;
  53.     DWORD iVertex;
  54.     PBYTE pvPoints;
  55.     D3DVERTEXELEMENT9 pDecl[MAX_FVF_DECL_SIZE];
  56.         
  57.     if ((m_pmcSelectedMesh == NULL) || m_pmcSelectedMesh->bPMMeshMode || (m_pmcSelectedMesh->pMesh == NULL))
  58.         return;
  59.  
  60.     hr = m_pmcSelectedMesh->pMesh->LockVertexBuffer(0, (LPVOID*)&pvPoints);
  61.     if (FAILED(hr))
  62.         return;
  63.  
  64.     m_pmcSelectedMesh->pMesh->GetDeclaration(pDecl);
  65.     cd.SetDeclaration(pDecl);
  66.  
  67.     // force normalized normals on mesh to tesselate
  68.     cVertices = m_pmcSelectedMesh->pMesh->GetNumVertices();
  69.     for (iVertex = 0; iVertex < cVertices; iVertex++)
  70.     {
  71.         pvNormal = cd.PvGetNormal(cd.GetArrayElem(pvPoints, iVertex));
  72.         D3DXVec3Normalize(pvNormal, pvNormal);
  73.     }
  74.  
  75.     m_pmcSelectedMesh->pMesh->UnlockVertexBuffer();
  76.     return;
  77. }
  78.  
  79. void ConvertCarriageReturns(char *szInput, char **pszOutput)
  80. {
  81.     DWORD cch;
  82.     DWORD cLineFeeds;
  83.     char *pchSrc;
  84.     char *pchDest;
  85.  
  86.     GXASSERT(pszOutput != NULL);
  87.  
  88.     cch = 1;  // for the null char
  89.     cLineFeeds = 0;
  90.     pchSrc = szInput;
  91.     while (*pchSrc != '\0')
  92.     {
  93.         if (*pchSrc == '\n')
  94.             cLineFeeds += 1;
  95.  
  96.         cch += 1;
  97.         pchSrc++;
  98.     }
  99.  
  100.     *pszOutput = new char[cch + cLineFeeds];
  101.     if (*pszOutput == NULL)
  102.         return;
  103.  
  104.     pchSrc = szInput;
  105.     pchDest = *pszOutput;
  106.     while (*pchSrc != '\0')
  107.     {
  108.         if (*pchSrc == '\n')
  109.         {
  110.             *pchDest = '\r';
  111.             pchDest++;
  112.         }
  113.  
  114.         *pchDest = *pchSrc;
  115.  
  116.         pchSrc++;
  117.         pchDest++;
  118.     }
  119.     *pchDest = '\0';
  120.  
  121.     return;
  122. }
  123.  
  124. void 
  125. TrivialData::CleanMesh()
  126. {
  127.     LPD3DXMESH pMeshFixed;
  128.     HRESULT hr;
  129.     DWORD *pdwSwap;
  130.     LPD3DXBUFFER pbufVertRemap = NULL;
  131.     LPD3DXBUFFER pbufOutput = NULL;
  132.     char *pbOutput;
  133.  
  134.     if ((m_pmcSelectedMesh == NULL) || m_pmcSelectedMesh->bPMMeshMode || (m_pmcSelectedMesh->pMesh == NULL))
  135.         return;
  136.  
  137.     hr = D3DXCleanMesh(D3DXCLEAN_SIMPLIFICATION, m_pmcSelectedMesh->pMesh, m_pmcSelectedMesh->rgdwAdjacency, &pMeshFixed, m_pmcSelectedMesh->rgdwAdjacency, &pbufOutput);
  138.     if (pbufOutput)
  139.     {
  140.         ConvertCarriageReturns((char*)pbufOutput->GetBufferPointer(), &pbOutput);
  141.         pvDialogData = (PVOID)pbOutput;
  142.  
  143.         DialogBox(m_hInstance, (LPCTSTR) IDD_INFO, m_hwnd, (DLGPROC) DlgProcOutput);
  144.  
  145.         delete []pbOutput;
  146.         GXRELEASE(pbufOutput);
  147.     }
  148.  
  149.     if (FAILED(hr))
  150.     {
  151.         goto e_Exit;
  152.     }
  153.  
  154.     GXRELEASE(m_pmcSelectedMesh->pMesh);
  155.     GXRELEASE(m_pmcSelectedMesh->ptmDrawMesh);
  156.     m_pmcSelectedMesh->pMesh = pMeshFixed;
  157.     m_pmcSelectedMesh->ptmDrawMesh = pMeshFixed;
  158.     pMeshFixed->AddRef();
  159.  
  160.     hr = D3DXValidMesh(m_pmcSelectedMesh->pMesh, m_pmcSelectedMesh->rgdwAdjacency, &pbufOutput);
  161.     if (pbufOutput)
  162.     {
  163.         ConvertCarriageReturns((char*)pbufOutput->GetBufferPointer(), &pbOutput);
  164.         pvDialogData = (PVOID)pbOutput;
  165.  
  166.         DialogBox(m_hInstance, (LPCTSTR) IDD_INFO, m_hwnd, (DLGPROC) DlgProcOutput);
  167.  
  168.         delete []pbOutput;
  169.     }
  170.  
  171.     if (FAILED(hr))
  172.     {
  173.         goto e_Exit;
  174.     }
  175.  
  176. e_Exit:
  177.     GXRELEASE(pbufOutput);
  178.     return;
  179. }
  180.  
  181. // control window to w
  182. INT_PTR CALLBACK
  183. DlgProcSplitMesh(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  184. {
  185.     WORD nId = 0, nNotifyCode = 0;
  186.     char szBuf[1024];
  187.     char *pTmp;
  188.     HRESULT hr;
  189.     DWORD iSplitSize = (DWORD)(UINT_PTR)g_pData->pvDialogData;
  190.  
  191.     GXASSERT(g_pData->m_pmcSelectedMesh != NULL);
  192.     GXASSERT(g_pData->m_pmcSelectedMesh->ptmDrawMesh != NULL);
  193.  
  194.     switch (message)
  195.     {
  196.     case WM_SETFONT:
  197.         return TRUE;
  198.  
  199.     case WM_INITDIALOG:
  200.         sprintf(szBuf, "%d", g_pData->m_pmcSelectedMesh->ptmDrawMesh->GetNumFaces());
  201.         SetDlgItemText(hDlg, IDC_SPLITMESH_FACES, szBuf);
  202.  
  203.         sprintf(szBuf, "%d", g_pData->m_pmcSelectedMesh->ptmDrawMesh->GetNumVertices());
  204.         SetDlgItemText(hDlg, IDC_SPLITMESH_VERTICES, szBuf);
  205.  
  206.         sprintf(szBuf, "%d", iSplitSize);
  207.         SetDlgItemText(hDlg, IDC_SPLITMESH_SPLITSIZE, szBuf);
  208.  
  209.         return TRUE;
  210.  
  211.     case WM_COMMAND:
  212.         nId = LOWORD(wParam);
  213.         nNotifyCode = HIWORD(wParam);
  214.         switch (nId)
  215.         {
  216.         case IDOK:
  217.             GetDlgItemText(hDlg, IDC_SPLITMESH_SPLITSIZE, szBuf, 256);
  218.             iSplitSize = (long) strtoul(szBuf, &pTmp, 10);
  219.             if (pTmp && (*pTmp != '\0'))
  220.                 goto e_Exit;
  221.  
  222.             g_pData->pvDialogData = (PVOID)(UINT_PTR)iSplitSize;
  223.  
  224.             EndDialog(hDlg, 0);
  225.  
  226.             return TRUE;
  227.         case IDCANCEL:
  228.             EndDialog(hDlg, 1);
  229.             return TRUE;
  230.         }
  231.         break;
  232.     }
  233.     return FALSE;
  234.  
  235. e_Exit:
  236.     MessageBox(NULL, "Please enter a valid number", "SplitMesh", MB_SYSTEMMODAL | MB_OK );
  237.     return TRUE;
  238. }
  239.  
  240. HRESULT TrivialData::SplitMesh()
  241. {
  242.     HRESULT hr = S_OK;
  243.  
  244.     DWORD ipattr;
  245.     DWORD iMesh;
  246.     DWORD dwOptions;
  247.     DWORD iSplitSize;
  248.     INT_PTR dwRet;
  249.     LPD3DXBUFFER pbufMeshes = NULL;
  250.     LPD3DXBUFFER pbufAdjacencies = NULL;
  251.     LPD3DXMESH *rgpMeshes = NULL;
  252.     DWORD **rgdwAdjacencies;
  253.     DWORD cNewMeshes;
  254.     SMeshContainer *pmcNew;
  255.     SMeshContainer *pmcTemp;
  256.  
  257.     if ((m_pmcSelectedMesh != NULL) && (m_pmcSelectedMesh->pMesh != NULL))
  258.     {
  259.         if (m_pmcSelectedMesh->bPMMeshMode || m_pmcSelectedMesh->bSimplifyMode || m_pmcSelectedMesh->bNPatchMode || m_pmcSelectedMesh->bTesselateMode)
  260.             goto e_Exit;
  261.  
  262.         pvDialogData = (PVOID)(UINT_PTR)1000;
  263.         dwRet = DialogBox(m_hInstance, MAKEINTRESOURCE(IDD_SPLITMESH), m_hwnd, (DLGPROC) DlgProcSplitMesh);
  264.         if (dwRet != 0)
  265.         {
  266.             hr = E_FAIL;
  267.             goto e_Exit;
  268.         }
  269.         iSplitSize = (DWORD)(UINT_PTR)pvDialogData;
  270.         
  271.         GXASSERT(m_pmcSelectedMesh->ptmDrawMesh != NULL);
  272.         GXASSERT(m_pmcSelectedMesh->pMesh != NULL);
  273.  
  274.         GXASSERT(m_pmcSelectedMesh->pPMMesh == NULL);
  275.         GXASSERT(m_pmcSelectedMesh->pSimpMesh == NULL);
  276.         GXASSERT(m_pmcSelectedMesh->pMeshToTesselate == NULL);
  277.         GXASSERT(m_pmcSelectedMesh->pPatchMesh == NULL);
  278.  
  279.         // if split size over 16 bit barrier, leave alone, otherwise remove 32bit flag
  280.         if (iSplitSize >= UNUSED16)
  281.             dwOptions = m_pmcSelectedMesh->pMesh->GetOptions();
  282.         else // 16 bit, so remove 32 bit flag if present
  283.             dwOptions = m_pmcSelectedMesh->pMesh->GetOptions() & ~D3DXMESH_32BIT;
  284.  
  285.         hr = D3DXSplitMesh(m_pmcSelectedMesh->pMesh, m_pmcSelectedMesh->rgdwAdjacency, iSplitSize, 
  286.                                             dwOptions, &cNewMeshes, &pbufMeshes, &pbufAdjacencies, 
  287.                                             NULL, NULL);
  288.         if (FAILED(hr))
  289.             goto e_Exit;
  290.  
  291.         // do this now, otherwise the Optimize call will have problems
  292.         m_dwFaceSelected = UNUSED32;
  293.         m_dwVertexSelected = UNUSED32;
  294.         UpdateSelectionInfo();
  295.  
  296.         rgpMeshes = (LPD3DXMESH*)pbufMeshes->GetBufferPointer();
  297.         rgdwAdjacencies = (DWORD**)pbufAdjacencies->GetBufferPointer();
  298.  
  299. #if 0
  300.         DWORD **rgpdwVertRemaps, **rgpdwFaceRemaps;
  301.         rgpdwVertRemaps = (DWORD**)pbufVertRemaps->GetBufferPointer();
  302.         rgpdwFaceRemaps = (DWORD**)pbufFaceRemaps->GetBufferPointer();
  303.  
  304.         {
  305.             DXCrackFVF cfvf(m_pmcSelectedMesh->pMesh->GetFVF());
  306.             PBYTE pbSrc;
  307.             PBYTE pbDest;
  308.             DWORD iMesh;
  309.             DWORD iVert;
  310.             m_pmcSelectedMesh->pMesh->LockVertexBuffer(D3DLOCK_READONLY, (LPVOID*)&pbSrc);
  311.  
  312.             for (iMesh = 0; iMesh < cNewMeshes; iMesh++)
  313.             {
  314.                 rgpMeshes[iMesh]->LockVertexBuffer(D3DLOCK_READONLY, (LPVOID*)&pbDest);
  315.  
  316.                 for (iVert = 0; iVert < rgpMeshes[iMesh]->GetNumVertices();iVert++)
  317.                 {
  318.                     if (memcmp(cfvf.GetArrayElem(pbDest, iVert), cfvf.GetArrayElem(pbSrc, rgpdwVertRemaps[iMesh][iVert]), cfvf.m_cBytesPerVertex) != 0)
  319.                     {
  320.                         // vertex remap is wrong!
  321.                         GXASSERT(0);
  322.                     }
  323.  
  324.                 }
  325.  
  326.                 rgpMeshes[iMesh]->UnlockVertexBuffer();
  327.             }
  328.  
  329.             m_pmcSelectedMesh->pMesh->UnlockVertexBuffer();
  330.         }
  331. #endif
  332.  
  333.         // remove references to the original mesh from the mesh container
  334.         //   that is being reused
  335.         GXRELEASE(m_pmcSelectedMesh->ptmDrawMesh);
  336.         GXRELEASE(m_pmcSelectedMesh->pMesh);
  337.         delete []m_pmcSelectedMesh->rgdwAdjacency;
  338.         m_pmcSelectedMesh->rgdwAdjacency = NULL;
  339.  
  340.  
  341.         m_pmcSelectedMesh->ptmDrawMesh = rgpMeshes[0];
  342.         m_pmcSelectedMesh->ptmDrawMesh->AddRef();
  343.         m_pmcSelectedMesh->pMesh = rgpMeshes[0];
  344.         m_pmcSelectedMesh->pMesh->AddRef();
  345.         m_pmcSelectedMesh->rgdwAdjacency = new DWORD[rgpMeshes[0]->GetNumFaces()*3];
  346.         if (m_pmcSelectedMesh->rgdwAdjacency == NULL) 
  347.         {
  348.             hr = E_OUTOFMEMORY;
  349.             goto e_Exit;
  350.         }
  351.         memcpy(m_pmcSelectedMesh->rgdwAdjacency, rgdwAdjacencies[0], sizeof(DWORD)*3*rgpMeshes[0]->GetNumFaces());
  352.  
  353.         Optimize(D3DXMESHOPT_ATTRSORT);
  354.  
  355.         // link in all the new mesh containers
  356.         for (iMesh = 1; iMesh < cNewMeshes; iMesh++)
  357.         {
  358.             pmcNew = new SMeshContainer();
  359.             if (pmcNew == NULL)
  360.             {
  361.                 hr = E_OUTOFMEMORY;
  362.                 goto e_Exit;
  363.             }
  364.  
  365.             pmcNew->ptmDrawMesh = rgpMeshes[iMesh];
  366.             pmcNew->ptmDrawMesh->AddRef();
  367.             pmcNew->pMesh = rgpMeshes[iMesh];
  368.             pmcNew->pMesh->AddRef();
  369.             pmcNew->rgdwAdjacency = new DWORD[rgpMeshes[iMesh]->GetNumFaces()*3];
  370.             if (pmcNew->rgdwAdjacency == NULL) 
  371.             {
  372.                 hr = E_OUTOFMEMORY;
  373.                 goto e_Exit;
  374.             }
  375.             memcpy(pmcNew->rgdwAdjacency, rgdwAdjacencies[iMesh], sizeof(DWORD)*3*rgpMeshes[iMesh]->GetNumFaces());
  376.     
  377.             pmcTemp = m_pmcSelectedMesh;
  378.             m_pmcSelectedMesh = pmcNew;
  379.             Optimize(D3DXMESHOPT_ATTRSORT);
  380.             m_pmcSelectedMesh = pmcTemp;
  381.  
  382.             // copy the attribute bundle
  383.             {
  384.                 pmcNew->m_cAttributeGroups = m_pmcSelectedMesh->m_cAttributeGroups;
  385.                 pmcNew->NumMaterials = m_pmcSelectedMesh->NumMaterials;
  386.                 pmcNew->m_rgpfxAttributes = new LPD3DXEFFECT[pmcNew->NumMaterials];
  387.                 pmcNew->m_rgEffectInfo = new SEffectInfo[pmcNew->NumMaterials];
  388.                 pmcNew->rgMaterials = new D3DXMATERIAL[pmcNew->NumMaterials];
  389.                 if ((pmcNew->m_rgpfxAttributes == NULL) || (pmcNew->m_rgEffectInfo == NULL) || (pmcNew->rgMaterials == NULL))
  390.                 {
  391.                     hr = E_OUTOFMEMORY;
  392.                     goto e_Exit;
  393.                 }
  394.  
  395.                 for (ipattr = 0; ipattr < pmcNew->NumMaterials; ipattr++)
  396.                 {
  397.                     pmcNew->rgMaterials[ipattr] = m_pmcSelectedMesh->rgMaterials[ipattr];
  398.                     if (pmcNew->rgMaterials[ipattr].pTextureFilename != NULL)
  399.                     {
  400.                         DWORD cchFilename = strlen(pmcNew->rgMaterials[ipattr].pTextureFilename)+1;
  401.  
  402.                         pmcNew->rgMaterials[ipattr].pTextureFilename = new char[cchFilename];
  403.                         if (pmcNew->rgMaterials[ipattr].pTextureFilename == NULL)
  404.                         {
  405.                             hr = E_OUTOFMEMORY;
  406.                             goto e_Exit;
  407.                         }
  408.  
  409.                         memcpy(pmcNew->rgMaterials[ipattr].pTextureFilename, m_pmcSelectedMesh->rgMaterials[ipattr].pTextureFilename, cchFilename);
  410.                     }
  411.  
  412.                     // UNDONE UNDONE Need to replicate effects!
  413.                     pmcNew->m_rgpfxAttributes[ipattr] = NULL;
  414.                     memset(&pmcNew->m_rgEffectInfo[ipattr], 0xff, sizeof(SEffectInfo));
  415.                 }
  416.             }
  417.  
  418.             pmcNew->pNextMeshContainer = m_pmcSelectedMesh->pNextMeshContainer;
  419.             m_pmcSelectedMesh->pNextMeshContainer = pmcNew;
  420.         }
  421.     }
  422.  
  423.     UpdateMeshMenu();
  424. e_Exit:
  425.  
  426.     if (rgpMeshes)
  427.     {
  428.         for (iMesh = 0; iMesh < cNewMeshes; iMesh++)
  429.         {
  430.             GXRELEASE(rgpMeshes[iMesh]);
  431.         }
  432.     }
  433.     GXRELEASE(pbufMeshes);
  434.     GXRELEASE(pbufAdjacencies);
  435.  
  436.     return hr;
  437. }
  438.  
  439. void
  440. TrivialData::Displace()
  441. {
  442.     if ((m_pmcSelectedMesh != NULL) && (m_pmcSelectedMesh->pMesh != NULL))
  443.     {
  444.         // standard mesh selected, displace to your heart's content
  445.  
  446.  
  447.         MessageBox(NULL, "h", "h", MB_OK);
  448.     }
  449. }
  450.  
  451.  
  452. // -------------------------------------------------------------------------------
  453. //  function    FindEdge
  454. //
  455. //   devnote    Simple helper function to determine which edge of a neighbor
  456. //                  face, points back to the given face
  457. //                  the pwIndices array is a three element array specifiying 
  458. //                  neighbors to a triangle face  
  459. //
  460. //   returns    if < 3, then iFaceSearch is the position in the given neighbor posiistion
  461. //                      else when >= 3, the face is not in the given array
  462. //
  463. template<class UINT_IDX>
  464. inline UINT
  465. FindEdge(UINT_IDX *rgiIndices, UINT_IDX iFaceSearch)
  466. {
  467.     UINT iNeighborEdge;
  468.  
  469.     // find the edge that points to this triangle in the neighbor
  470.     for (iNeighborEdge = 0; iNeighborEdge < 3; iNeighborEdge++)
  471.     {
  472.         if (rgiIndices[iNeighborEdge] == iFaceSearch)
  473.         {
  474.             break;
  475.         }
  476.     }
  477.  
  478.     return iNeighborEdge;
  479. }
  480. #if 0
  481. // return true if two normals are not binary equivalent
  482. BOOL BNormalsDifferent
  483.     (
  484.     DXCrackFVF &cfvf, 
  485.     PBYTE pbVertex1,
  486.     PBYTE pbVertex2
  487.     )
  488. {
  489.     return (memcmp(cfvf.PvGetNormal(pbVertex1), cfvf.PvGetNormal(pbVertex2), sizeof(D3DXVECTOR3)) != 0);
  490. }
  491.  
  492. template<class UINT_IDX>
  493. HRESULT WINAPI 
  494. D3DXFixNPatchCreasesEx
  495.     (
  496.     LPD3DXMESH pMeshIn, 
  497.     DWORD *rgdwAdjacencyIn,
  498.     LPD3DXMESH *ppMeshOut,
  499.     LPD3DXBUFFER *ppbufAdjacencyOut,
  500.     UINT_IDX Bogus
  501.     )
  502. {
  503.     HRESULT hr = S_OK;
  504.     DWORD iFace;
  505.     DWORD cFaces;
  506.     DWORD cVertices;
  507.     DWORD dwOptions;
  508.     UINT_IDX *rgwIndices = NULL;
  509.     UINT_IDX *rgwIndicesOut = NULL;
  510.     LPDIRECT3DDEVICE9 pDevice = NULL;
  511.     DWORD iEdge1; 
  512.     DWORD iEdge2; 
  513.     DWORD iNEdge1;
  514.     DWORD iNEdge2;
  515.     PBYTE pbVertices = NULL;
  516.     PBYTE pbVerticesOut = NULL;
  517.     DWORD *rgdwAttribs = NULL;
  518.     DWORD *rgdwAttribsOut = NULL;
  519.     DWORD iPoint;
  520.     DWORD iNeighborPoint;
  521.     DWORD iNeighbor;
  522.     DWORD *rgdwAdjCur;
  523.     DWORD cNewFaces;
  524.     DWORD cFacesOut;
  525.     DXCrackFVF cfvf(D3DFVF_XYZ);
  526.     LPD3DXMESH pMeshOut;
  527.     DWORD iFaceOutCur;
  528.     DWORD iFaceOutNext;
  529.     DWORD cAttribs;
  530.  
  531.     if ((pMeshIn == NULL) || (rgdwAdjacencyIn == NULL) || (ppMeshOut == NULL))
  532.     {
  533. #ifdef DBG
  534.         if (pMeshIn == NULL)
  535.             DPF(0, "D3DXFixNPatchCreases: A mesh must be provided");
  536.         else if (rgdwAdjacencyIn == NULL)
  537.             DPF(0, "D3DXFixNPatchCreases: Input adjacency must be provided");
  538.         else if (ppMeshOut == NULL)
  539.             DPF(0, "D3DXFixNPatchCreases: Output mesh pointer must be provided");
  540. #endif
  541.         hr = D3DERR_INVALIDCALL;
  542.         goto e_Exit;
  543.     }
  544.  
  545.     dwOptions = pMeshIn->GetOptions();
  546.     if (dwOptions & D3DXMESH_WRITEONLY)
  547.     {
  548.         DPF(0, "D3DXFixNPatchCreases: Input mesh index/vertex buffers must not be WRITE-ONLY");
  549.         hr = D3DERR_INVALIDCALL;
  550.         goto e_Exit;
  551.     }
  552.  
  553.     cFaces = pMeshIn->GetNumFaces();
  554.     cVertices = pMeshIn->GetNumVertices();
  555.  
  556.     cfvf = DXCrackFVF(pMeshIn->GetFVF());
  557.  
  558.     hr = pMeshIn->GetDevice(&pDevice);
  559.     if (FAILED(hr))
  560.         goto e_Exit;
  561.  
  562.     hr = pMeshIn->LockIndexBuffer(D3DLOCK_READONLY, (LPVOID*)&rgwIndices);
  563.     if (FAILED(hr))
  564.         goto e_Exit;
  565.  
  566.     hr = pMeshIn->LockVertexBuffer(D3DLOCK_READONLY, (LPVOID*)&pbVertices);
  567.     if (FAILED(hr))
  568.         goto e_Exit;
  569.  
  570.     cNewFaces = 0;
  571.     rgdwAdjCur = rgdwAdjacencyIn;
  572.     for (iFace = 0; iFace < cFaces; iFace++)
  573.     {
  574.         for (iPoint = 0; iPoint < 3; iPoint++)
  575.         {
  576.             // if adjacent to another face, and this faces index is less, then look to see if there is a crease
  577.             if ((rgdwAdjCur[iPoint] > iFace) && (rgdwAdjCur[iPoint] != UNUSED32))
  578.             {
  579.                 iNeighbor = rgdwAdjCur[iPoint];
  580.                 iNeighborPoint = FindEdge(rgdwAdjacencyIn + iNeighbor*3, iFace);
  581.  
  582.                 iEdge1 = iFace*3 + iPoint;
  583.                 iEdge2 = iFace*3 + (iPoint+1)%3;
  584.                 iNEdge1 = iNeighbor*3 + iNeighborPoint;
  585.                 iNEdge2 = iNeighbor*3 + (iNeighborPoint+1)%3;
  586.  
  587.  
  588.                 if ((rgwIndices[iEdge1] != rgwIndices[iNEdge2])
  589.                        && BNormalsDifferent(cfvf, cfvf.GetArrayElem(pbVertices, rgwIndices[iEdge1]),
  590.                                                   cfvf.GetArrayElem(pbVertices, rgwIndices[iNEdge2])))
  591.                 {
  592.                     cNewFaces += 1;
  593.                 }
  594.  
  595.                 if ((rgwIndices[iEdge2] != rgwIndices[iNEdge1])
  596.                        && BNormalsDifferent(cfvf, cfvf.GetArrayElem(pbVertices, rgwIndices[iEdge2]),
  597.                                                   cfvf.GetArrayElem(pbVertices, rgwIndices[iNEdge1])))
  598.                 {
  599.                     cNewFaces += 1;
  600.                 }
  601.             }
  602.         }
  603.  
  604.         rgdwAdjCur += 3;  // move to next face
  605.     }
  606.  
  607.     cFacesOut = cFaces + cNewFaces;
  608.  
  609.     hr = D3DXCreateMeshFVF(cFacesOut, cVertices, dwOptions, pMeshIn->GetFVF(), pDevice, &pMeshOut);
  610.     if (FAILED(hr))
  611.         goto e_Exit;
  612.  
  613.     hr = pMeshOut->LockVertexBuffer(0, (LPVOID*)&pbVerticesOut);
  614.     if (FAILED(hr))
  615.         goto e_Exit;
  616.  
  617.     hr = pMeshIn->LockAttributeBuffer(D3DLOCK_READONLY, &rgdwAttribs);
  618.     if (FAILED(hr))
  619.         goto e_Exit;
  620.  
  621.     hr = pMeshOut->LockAttributeBuffer(0, &rgdwAttribsOut);
  622.     if (FAILED(hr))
  623.         goto e_Exit;
  624.  
  625.     hr = pMeshOut->LockIndexBuffer(0, (LPVOID*)&rgwIndicesOut);
  626.     if (FAILED(hr))
  627.         goto e_Exit;
  628.  
  629.     memcpy(pbVerticesOut, pbVertices, cfvf.m_cBytesPerVertex * cVertices);
  630.  
  631.     rgdwAdjCur = rgdwAdjacencyIn;
  632.  
  633.     iFaceOutCur = 0;
  634.     iFaceOutNext = 0;
  635.     
  636.     for (iFace = 0; iFace < cFaces; iFace++)
  637.     {
  638.  
  639.         // copy the current face
  640.         memcpy(rgwIndicesOut + (iFaceOutNext*3), rgwIndices + (iFace*3), sizeof(UINT_IDX)*3);
  641.         rgdwAttribsOut[iFaceOutNext] = rgdwAttribs[iFace];
  642.  
  643.         iFaceOutNext += 1;
  644.         
  645.         // now decide if we need to insert any faces
  646.         for (iPoint = 0; iPoint < 3; iPoint++)
  647.         {
  648.             // if adjacent to another face, and this faces index is less, then look to see if there is a crease
  649.             if ((rgdwAdjCur[iPoint] > iFace) && (rgdwAdjCur[iPoint] != UNUSED32))
  650.             {
  651.                 iNeighbor = rgdwAdjCur[iPoint];
  652.                 iNeighborPoint = FindEdge(rgdwAdjacencyIn + iNeighbor*3, iFace);
  653.  
  654.                 iEdge1 = iFace*3 + iPoint;
  655.                 iEdge2 = iFace*3 + (iPoint+1)%3;
  656.                 iNEdge1 = iNeighbor*3 + iNeighborPoint;
  657.                 iNEdge2 = iNeighbor*3 + (iNeighborPoint+1)%3;
  658.  
  659.                 if ((rgwIndices[iEdge1] != rgwIndices[iNEdge2])
  660.                        && BNormalsDifferent(cfvf, cfvf.GetArrayElem(pbVertices, rgwIndices[iEdge1]),
  661.                                                   cfvf.GetArrayElem(pbVertices, rgwIndices[iNEdge2])))
  662.                 {
  663.                     rgwIndicesOut[iFaceOutNext*3 + 0] = rgwIndices[iEdge2];
  664.                     rgwIndicesOut[iFaceOutNext*3 + 1] = rgwIndices[iEdge1];
  665.                     rgwIndicesOut[iFaceOutNext*3 + 2] = rgwIndices[iNEdge2];
  666.                     rgdwAttribsOut[iFaceOutNext] = rgdwAttribs[iFace];
  667.                     iFaceOutNext += 1;
  668.                 }
  669.  
  670.                 if ((rgwIndices[iEdge2] != rgwIndices[iNEdge1])
  671.                        && BNormalsDifferent(cfvf, cfvf.GetArrayElem(pbVertices, rgwIndices[iEdge2]),
  672.                                                   cfvf.GetArrayElem(pbVertices, rgwIndices[iNEdge1])))
  673.                 {
  674.                     rgwIndicesOut[iFaceOutNext*3 + 0] = rgwIndices[iNEdge2];
  675.                     rgwIndicesOut[iFaceOutNext*3 + 1] = rgwIndices[iNEdge1];
  676.                     rgwIndicesOut[iFaceOutNext*3 + 2] = rgwIndices[iEdge2];
  677.                     rgdwAttribsOut[iFaceOutNext] = rgdwAttribs[iFace];
  678.                     iFaceOutNext += 1;
  679.                 }
  680.             }
  681.         }
  682.  
  683.         iFaceOutCur = iFaceOutNext;
  684.         rgdwAdjCur += 3;  // move to next face
  685.     }
  686.  
  687.     hr = pMeshIn->GetAttributeTable(NULL, &cAttribs);
  688.     if (FAILED(hr))
  689.         goto e_Exit;
  690.  
  691.     // if already attribute sorted, then resort now.  should be a no-op, just rebuild the table
  692.     if (cAttribs > 0)
  693.     {
  694.         hr = pMeshOut->OptimizeInplace(D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL);
  695.         if (FAILED(hr))
  696.             goto e_Exit;
  697.     }
  698.  
  699.     if (ppbufAdjacencyOut)
  700.     {
  701.         // adjacency not yet supported for output
  702.         GXASSERT(0);
  703.  
  704.         hr = D3DXCreateBuffer(sizeof(DWORD)*3*cFacesOut, ppbufAdjacencyOut);
  705.         if (FAILED(hr))
  706.             goto e_Exit;
  707.  
  708.         // for now, set everything to UNUSED
  709.         memset((*ppbufAdjacencyOut)->GetBufferPointer(), 0xff, sizeof(DWORD)*3*cFacesOut);
  710.     }
  711.  
  712.     *ppMeshOut = pMeshOut;
  713.     pMeshOut->AddRef();
  714.  
  715. e_Exit:
  716.     if (rgwIndices != NULL)
  717.     {
  718.         pMeshIn->UnlockIndexBuffer();
  719.     }
  720.     if (pbVertices != NULL)
  721.     {
  722.         pMeshIn->UnlockVertexBuffer();
  723.     }
  724.     if (rgwIndicesOut != NULL)
  725.     {
  726.         pMeshOut->UnlockIndexBuffer();
  727.     }
  728.     if (pbVertices != NULL)
  729.     {
  730.         pMeshOut->UnlockVertexBuffer();
  731.     }
  732.  
  733.     if (rgdwAttribs != NULL)
  734.     {
  735.         pMeshIn->UnlockAttributeBuffer();
  736.     }
  737.     if (rgdwAttribsOut != NULL)
  738.     {
  739.         pMeshOut->UnlockAttributeBuffer();
  740.     }
  741.  
  742.     GXRELEASE(pDevice);
  743.     GXRELEASE(pMeshOut);
  744.  
  745.     return hr;
  746. }
  747.  
  748. HRESULT WINAPI 
  749. D3DXFixNPatchCreases
  750.     (
  751.     LPD3DXMESH pMeshIn, 
  752.     DWORD *rgdwAdjacencyIn,
  753.     LPD3DXMESH *ppMeshOut,
  754.     LPD3DXBUFFER *ppbufAdjacencyOut
  755.     )
  756. {
  757.     unsigned int dwBogus = 0;
  758.     unsigned short wBogus = 0;
  759.  
  760.     if (pMeshIn == NULL) 
  761.     {
  762.         DPF(0, "D3DXFixNPatchCreases: A mesh must be provided");
  763.         return D3DERR_INVALIDCALL;
  764.     }
  765.  
  766.     if (pMeshIn->GetOptions() & D3DXMESH_32BIT)
  767.         return D3DXFixNPatchCreasesEx<unsigned int>(pMeshIn, rgdwAdjacencyIn, ppMeshOut, ppbufAdjacencyOut, dwBogus);
  768.     else
  769.         return D3DXFixNPatchCreasesEx<unsigned short>(pMeshIn, rgdwAdjacencyIn, ppMeshOut, ppbufAdjacencyOut, wBogus);
  770.  
  771. }
  772.  
  773. void 
  774. TrivialData::FixNPatchCreases()
  775. {
  776.     HRESULT hr;
  777.     LPD3DXMESH pMeshNew;
  778.     LPD3DXBUFFER pbufAdjacencyNew;
  779.  
  780.     if ((m_pmcSelectedMesh != NULL) && (m_pmcSelectedMesh->pMesh != NULL))
  781.     {
  782.         hr = D3DXFixNPatchCreases(m_pmcSelectedMesh->pMesh, m_pmcSelectedMesh->rgdwAdjacency, &pMeshNew, &pbufAdjacencyNew);
  783.         if (FAILED(hr))
  784.             goto e_Exit;
  785.  
  786.         GXRELEASE(m_pmcSelectedMesh->pMesh);
  787.         GXRELEASE(m_pmcSelectedMesh->ptmDrawMesh);
  788.         m_pmcSelectedMesh->pMesh = pMeshNew;
  789.         m_pmcSelectedMesh->ptmDrawMesh = pMeshNew;
  790.         m_pmcSelectedMesh->ptmDrawMesh->AddRef();
  791.  
  792.         delete m_pmcSelectedMesh->rgdwAdjacency;
  793.  
  794.         m_pmcSelectedMesh->rgdwAdjacency     = new DWORD [pbufAdjacencyNew->GetBufferSize() / sizeof(DWORD)];
  795.         if(m_pmcSelectedMesh->rgdwAdjacency == NULL)
  796.         {
  797.             hr = E_OUTOFMEMORY;
  798.             goto e_Exit;
  799.         }
  800.  
  801.         memcpy(m_pmcSelectedMesh->rgdwAdjacency, pbufAdjacencyNew->GetBufferPointer(), pbufAdjacencyNew->GetBufferSize());
  802.  
  803.         m_pmcSelectedMesh->UpdateViews(m_pdeSelected);
  804.     }
  805.  
  806. e_Exit:
  807.     return;
  808. }
  809. #endif
  810.  
  811. HRESULT TrivialData::TesselateFrame(SFrame *pframe)
  812. {
  813.     SMeshContainer *pmc;
  814.     HRESULT hr;
  815.  
  816.     if (pframe == NULL)
  817.         return S_OK;
  818.  
  819.     pmc = pframe->pmcMesh;
  820.     while (pmc != NULL)
  821.     {
  822.         hr = Tesselate(pmc, FALSE);
  823.         if (FAILED(hr))
  824.             return hr;
  825.  
  826.         pmc = (SMeshContainer*)pmc->pNextMeshContainer;
  827.     }
  828.  
  829.     return S_OK;
  830. }
  831.  
  832. HRESULT TrivialData::Tesselate(SMeshContainer *pmc, BOOL bSkipAdjacencyAndEdges)
  833. {
  834.     HRESULT hr = S_OK;
  835.     LPD3DXMESH pMeshOut = NULL;
  836.     LPD3DXBUFFER pAdjacencyOut = NULL;
  837.     DWORD iVertex;
  838.     DWORD cVertices;
  839.     PBYTE pvPoints;
  840.     D3DXVECTOR3 *pvNormal;
  841.     CD3DXCrackDecl1 cd;
  842.     D3DVERTEXELEMENT9 pDecl[MAX_FVF_DECL_SIZE];
  843.  
  844.     if (pmc == NULL)
  845.         return S_OK;
  846.  
  847.     if (pmc->pPatchMesh != NULL)
  848.     {
  849.         LPD3DXMESH pMesh;
  850.         D3DVERTEXELEMENT9 pDeclIn[MAX_FVF_DECL_SIZE];
  851.         D3DVERTEXELEMENT9 pDeclOut[MAX_FVF_DECL_SIZE];
  852.         DWORD cTriangles,cVertices,cTotTriangles,cTotVertices;
  853.  
  854.         D3DXVECTOR4 Trans = D3DXVECTOR4(0,0,1,1);
  855.  
  856.         hr = pmc->pPatchMesh->GetTessSize(pmc->cTesselateLevel + 1.0f, FALSE, &cTriangles,&cVertices);
  857.         if(FAILED(hr))
  858.             goto e_Exit;
  859.  
  860.         hr = pmc->pPatchMesh->GetDeclaration(pDeclIn);
  861.         if (FAILED(hr))
  862.             goto e_Exit;
  863.  
  864.         hr = D3DXGenerateOutputDecl(pDeclOut, pDeclIn);
  865.         if (FAILED(hr))
  866.             goto e_Exit;
  867.  
  868.         hr = D3DXCreateMesh(cTriangles,cVertices,D3DXMESH_MANAGED,pDeclOut,m_pDevice,&pMesh);
  869.         if (FAILED(hr))
  870.             goto e_Exit;
  871.  
  872.   //      pmc->pPatchMesh->ComputeAdj(.05f,100000);
  873.  
  874.  
  875.         hr = pmc->pPatchMesh->Tessellate(pmc->cTesselateLevel + 1.0f, pMesh);
  876.         if (FAILED(hr))
  877.             goto e_Exit;
  878.  
  879.         delete []pmc->rgdwAdjacency;
  880.         pmc->rgdwAdjacency = new DWORD[pMesh->GetNumFaces()*3];
  881.         if (pmc->rgdwAdjacency == NULL)
  882.         {
  883.             hr = E_OUTOFMEMORY;
  884.             goto e_Exit;
  885.         }
  886.         pMesh->ConvertPointRepsToAdjacency(NULL, pmc->rgdwAdjacency);
  887.  
  888.         GXRELEASE(pmc->ptmDrawMesh);
  889.         pmc->ptmDrawMesh = pMesh;
  890.         pmc->pMesh = pMesh;
  891.         pMesh->AddRef();
  892.  
  893.         AdjustScrollbar();
  894.  
  895.         pmc->pMesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL);
  896.  
  897.         if (m_pdeSelected != NULL)
  898.             pmc->UpdateViews(m_pdeSelected);
  899.  
  900.     }
  901.     else if (pmc->pMesh != NULL)
  902.     {
  903.         if (!pmc->bNPatchMode)
  904.         {
  905.             if ( !(pmc->pMesh->GetFVF() & D3DFVF_NORMAL) )
  906.             {
  907.                 hr = E_INVALIDARG;
  908.                 goto e_Exit;
  909.             }
  910.  
  911.             pmc->pMesh->GetDeclaration(pDecl);
  912.             hr = pmc->pMesh->CloneMesh(pmc->pMesh->GetOptions()|D3DXMESH_NPATCHES,
  913.                                     pDecl, m_pDevice, &pmc->pMeshToTesselate);
  914.             if (FAILED(hr))
  915.                 goto e_Exit;
  916.  
  917.             GXRELEASE(pmc->pMesh);
  918.             GXRELEASE(pmc->ptmDrawMesh);
  919.             pmc->pMesh = pmc->pMeshToTesselate;
  920.             pmc->pMesh->AddRef();
  921.             pmc->ptmDrawMesh = pmc->pMeshToTesselate;
  922.             pmc->ptmDrawMesh->AddRef();
  923.  
  924.             hr = pmc->pMeshToTesselate->LockVertexBuffer(0, (LPVOID*)&pvPoints);
  925.             if (FAILED(hr))
  926.                 goto e_Exit;
  927.  
  928.             cd.SetDeclaration(pDecl);
  929.  
  930.             // force normalized normals on mesh to tesselate
  931.             cVertices = pmc->pMeshToTesselate->GetNumVertices();
  932.             for (iVertex = 0; iVertex < cVertices; iVertex++)
  933.             {
  934.                 pvNormal = cd.PvGetNormal(cd.GetArrayElem(pvPoints, iVertex));
  935.                 D3DXVec3Normalize(pvNormal, pvNormal);
  936.             }
  937.  
  938.             pmc->pMeshToTesselate->UnlockVertexBuffer();
  939.  
  940.             pmc->rgdwAdjacencyTesselate = pmc->rgdwAdjacency;
  941.             pmc->rgdwAdjacency = NULL;
  942.  
  943.             pmc->cTesselateLevel = 1;
  944.             pmc->bNPatchMode = TRUE;
  945.         }
  946.  
  947.         //if (!m_bHWNPatches)
  948.         {
  949.  
  950.             // only update SW skinned version if needed for drawing or not doing a "quick" normal update re-tesselate
  951.             if (!bSkipAdjacencyAndEdges || !m_bHWNPatches)
  952.             {
  953.                 hr = D3DXTessellateNPatches(pmc->pMeshToTesselate, 
  954.                                         pmc->rgdwAdjacencyTesselate,
  955.                                         (float)(pmc->cTesselateLevel + 1), 
  956.                                         TRUE,
  957.                                         &pMeshOut,
  958.                                         bSkipAdjacencyAndEdges ? NULL : &pAdjacencyOut);
  959.                 if (FAILED(hr))
  960.                 {
  961.                     // if a tesselate has succeeded, then we probably just overran the
  962.                     //   16 to 32bit limit, so continue on at the current level
  963.                     if (pmc->pSWTesselatedMesh != NULL)
  964.                     {
  965.                         hr = S_OK;
  966.                     }
  967.  
  968.                     goto e_Exit;
  969.                 }
  970.  
  971.                 if (!m_bHWNPatches)
  972.                 {
  973.                     GXRELEASE(pmc->pMesh);
  974.                     GXRELEASE(pmc->ptmDrawMesh);
  975.  
  976.                     // now replace the old mesh with the new one
  977.                     pmc->pMesh = pMeshOut;
  978.                     pmc->ptmDrawMesh = pMeshOut;
  979.                     pMeshOut->AddRef();
  980.                     pMeshOut->AddRef();
  981.                 }
  982.  
  983.                 // keep a SW copy for view/intersection purposes
  984.                 GXRELEASE(pmc->pSWTesselatedMesh);
  985.                 pmc->pSWTesselatedMesh = pMeshOut;
  986.             }
  987.  
  988.  
  989.             if (!bSkipAdjacencyAndEdges)
  990.             {
  991.                 // update adjacency information
  992.                 delete [] pmc->rgdwAdjacency;
  993.  
  994.                 pmc->rgdwAdjacency     = new DWORD [pAdjacencyOut->GetBufferSize() / sizeof(DWORD)];
  995.                 if (pmc->rgdwAdjacency == NULL)
  996.                 {
  997.                     hr = E_OUTOFMEMORY;
  998.                     goto e_Exit;
  999.                 }
  1000.  
  1001.                 memcpy(pmc->rgdwAdjacency, pAdjacencyOut->GetBufferPointer(), pAdjacencyOut->GetBufferSize());
  1002.                 pMeshOut->OptimizeInplace(D3DXMESHOPT_ATTRSORT, pmc->rgdwAdjacency, pmc->rgdwAdjacency, NULL, NULL);
  1003.  
  1004.                 //hr = pmc->m_aoAdjacency.Init(pmc->pMesh, pmc->rgdwAdjacency);
  1005.                 //if (FAILED(hr))
  1006.                     //goto e_Exit;
  1007.  
  1008.                 //hr = pmc->m_eoEdges.Init(pmc->pMesh, pmc->rgdwAdjacency);
  1009.                 //if (FAILED(hr))
  1010.                     //goto e_Exit;
  1011.  
  1012.                 hr = pmc->m_npoNPatchOutline.Init(pmc->pSWTesselatedMesh, pmc->cTesselateLevel + 1);
  1013.                 if (FAILED(hr))
  1014.                     goto e_Exit;
  1015.             }
  1016.             // optimize the SW mesh if being used for drawing and skipping most of mesh container setup
  1017.             else if (pMeshOut != NULL)
  1018.             {
  1019.                 pMeshOut->OptimizeInplace(D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL);
  1020.             }
  1021.  
  1022.             if (!bSkipAdjacencyAndEdges)
  1023.             {
  1024.                 AdjustScrollbar();
  1025.             }
  1026.         }
  1027.  
  1028.         // display normals from the mesh to tesselate from - consistent between hw and sw n-patching
  1029.         hr = pmc->m_snNormals.Init(pmc->pMeshToTesselate, UNUSED32, m_pdeSelected->fRadius / 20.0f);
  1030.         if (FAILED(hr))
  1031.             goto e_Exit;
  1032.  
  1033.         pmc->ptmDrawMesh->GetAttributeTable(m_pmcSelectedMesh->m_rgaeAttributeTable, NULL);
  1034.     }
  1035.  
  1036.  
  1037. e_Exit:
  1038.     GXRELEASE(pAdjacencyOut);
  1039.  
  1040.     if (FAILED(hr))
  1041.     {
  1042.         pmc->bNPatchMode = FALSE;
  1043.         GXRELEASE(pmc->pMeshToTesselate);
  1044.     }
  1045.     return hr;
  1046. }
  1047.  
  1048. void TrivialData::ConvertSelectedMesh
  1049.     (
  1050.     DWORD dwOptions, 
  1051.     LPD3DVERTEXELEMENT9 pDecl
  1052.     )
  1053. {
  1054.     HRESULT hr;
  1055.     LPD3DXPMESH pPMeshTemp;
  1056.     LPD3DXMESH pMeshTemp;
  1057.     D3DVERTEXELEMENT9 pDeclOrig[MAX_FVF_DECL_SIZE];
  1058.  
  1059.     GXASSERT(m_pmcSelectedMesh->ptmDrawMesh != NULL);
  1060.     GXASSERT(!m_pmcSelectedMesh->bSimplifyMode);
  1061.  
  1062.     // do not change the position type, will wreak havok with skinning
  1063. //    dwFVF &= ~D3DFVF_POSITION_MASK;
  1064. //    dwFVF |= m_pmcSelectedMesh->ptmDrawMesh->GetFVF() & D3DFVF_POSITION_MASK;
  1065.  
  1066.     m_pmcSelectedMesh->ptmDrawMesh->GetDeclaration(pDeclOrig);
  1067.  
  1068.     // if no changes, then just return
  1069.     if ((dwOptions == m_pmcSelectedMesh->ptmDrawMesh->GetOptions())
  1070.         && (BIdenticalDecls(pDecl, pDeclOrig)))
  1071.         return;
  1072.  
  1073.     if (m_pmcSelectedMesh->bPMMeshMode)
  1074.     {
  1075.         // make a drawable image of the current simplification mesh
  1076.         hr = m_pmcSelectedMesh->pPMMesh->ClonePMesh(dwOptions,
  1077.                                         pDecl, 
  1078.                                         m_pDevice, &pPMeshTemp);
  1079.         if (FAILED(hr))
  1080.             return;
  1081.  
  1082.         GXRELEASE(m_pmcSelectedMesh->ptmDrawMesh);
  1083.         GXRELEASE(m_pmcSelectedMesh->pPMMesh);
  1084.  
  1085.         m_pmcSelectedMesh->pPMMesh = pPMeshTemp;
  1086.  
  1087.         m_pmcSelectedMesh->ptmDrawMesh = pPMeshTemp;
  1088.         pPMeshTemp->AddRef();
  1089.     }
  1090.     else
  1091.     {
  1092.         hr = m_pmcSelectedMesh->pMesh->CloneMesh(dwOptions,
  1093.                                         pDecl, 
  1094.                                         m_pDevice, &pMeshTemp);
  1095.         if (FAILED(hr))
  1096.             return;
  1097.  
  1098.         GXRELEASE(m_pmcSelectedMesh->ptmDrawMesh);
  1099.         GXRELEASE(m_pmcSelectedMesh->pMesh);
  1100.  
  1101.         m_pmcSelectedMesh->pMesh = pMeshTemp;
  1102.  
  1103.         m_pmcSelectedMesh->ptmDrawMesh = pMeshTemp;
  1104.         pMeshTemp->AddRef();
  1105.     } 
  1106.  
  1107.     hr = m_pmcSelectedMesh->UpdateViews(m_pdeSelected);
  1108.     if (FAILED(hr))
  1109.         return;
  1110.  
  1111. }
  1112.  
  1113. void 
  1114. TrivialData::SetNumVertices(int cVerticesChange, bool bAbsolute)
  1115. {
  1116.     if (m_pmcSelectedMesh == NULL)
  1117.         return;
  1118.  
  1119.     BOOL bSimpMesh = m_pmcSelectedMesh->bSimplifyMode;
  1120.     BOOL bPMesh = m_pmcSelectedMesh->bPMMeshMode;
  1121.     DWORD cVerticesNew;
  1122.  
  1123.     // if not a LOD type of mesh, then return
  1124.     if (!bSimpMesh && !bPMesh)
  1125.         return;
  1126.  
  1127.     if (bAbsolute)
  1128.     {
  1129.         cVerticesNew = cVerticesChange;
  1130.     }
  1131.     else
  1132.     {
  1133.         if (bPMesh)
  1134.             cVerticesNew = m_pmcSelectedMesh->pPMMesh->GetNumVertices();
  1135.         else
  1136.             cVerticesNew = m_pmcSelectedMesh->pSimpMesh->GetNumVertices();
  1137.  
  1138.         if (cVerticesChange + (int)cVerticesNew < 1)
  1139.             cVerticesNew = 1;
  1140.         else
  1141.             cVerticesNew += cVerticesChange;
  1142.     }
  1143.  
  1144.     if (bPMesh)
  1145.     {
  1146.         if (cVerticesNew < m_pmcSelectedMesh->m_cMinVerticesSoft)
  1147.             cVerticesNew = m_pmcSelectedMesh->m_cMinVerticesSoft;
  1148.  
  1149.         if (cVerticesNew > m_pmcSelectedMesh->m_cMaxVerticesSoft)
  1150.             cVerticesNew = m_pmcSelectedMesh->m_cMaxVerticesSoft;
  1151.     }
  1152.  
  1153.     if (bPMesh)
  1154.         m_pmcSelectedMesh->pPMMesh->SetNumVertices(cVerticesNew);
  1155.     else
  1156.         m_pmcSelectedMesh->pSimpMesh->ReduceVertices(cVerticesNew);
  1157.  
  1158.     if (bSimpMesh)
  1159.     {
  1160.         GXRELEASE(m_pmcSelectedMesh->pMesh);
  1161.  
  1162.         // make a drawable image of the current simplification mesh
  1163.         m_pmcSelectedMesh->pSimpMesh->CloneMesh(m_pmcSelectedMesh->pSimpMesh->GetOptions(),
  1164.                                         NULL, 
  1165.                                         m_pDevice, NULL, NULL, &m_pmcSelectedMesh->pMesh);
  1166.  
  1167.         m_pmcSelectedMesh->ptmDrawMesh = m_pmcSelectedMesh->pMesh;
  1168.         m_pmcSelectedMesh->pMesh->AddRef();
  1169.     }
  1170.  
  1171.     // make certain that the selected face/vertex is still valid
  1172.     if (bPMesh && (m_dwFaceSelected != UNUSED32))
  1173.     {
  1174.         
  1175.         if ((m_dwVertexSelected >= m_pmcSelectedMesh->m_rgaeAttributeTable[m_dwFaceSelectedAttr].VertexStart + m_pmcSelectedMesh->m_rgaeAttributeTable[m_dwFaceSelectedAttr].VertexCount)
  1176.               || (m_dwFaceSelected >= m_pmcSelectedMesh->m_rgaeAttributeTable[m_dwFaceSelectedAttr].FaceStart + m_pmcSelectedMesh->m_rgaeAttributeTable[m_dwFaceSelectedAttr].FaceCount))
  1177.         {
  1178.             m_dwVertexSelected = UNUSED32;
  1179.             m_dwFaceSelected = UNUSED32;
  1180.             m_dwFaceSelectedAttr = UNUSED32;
  1181.         }
  1182.     }
  1183.  
  1184.     m_pmcSelectedMesh->ptmDrawMesh->GetAttributeTable(m_pmcSelectedMesh->m_rgaeAttributeTable, NULL);
  1185.  
  1186.     if (bPMesh)
  1187.     {
  1188.         m_pmcSelectedMesh->pPMMesh->GetAdjacency(m_pmcSelectedMesh->rgdwAdjacency);
  1189.         m_pmcSelectedMesh->UpdateViews(m_pdeSelected);
  1190.     }
  1191.  
  1192.     AdjustScrollbar();
  1193. }
  1194.  
  1195. void 
  1196. TrivialData::SetNumFaces(int cFacesChange, bool bAbsolute)
  1197. {
  1198.     BOOL bSimpMesh = m_pmcSelectedMesh->bSimplifyMode;
  1199.     BOOL bPMesh = m_pmcSelectedMesh->bPMMeshMode;
  1200.     DWORD cFacesNew;
  1201.  
  1202.     // if not a LOD type of mesh, then return
  1203.     if (!bSimpMesh && !bPMesh)
  1204.         return;
  1205.  
  1206.     if (bAbsolute)
  1207.     {
  1208.         cFacesNew = cFacesChange;
  1209.     }
  1210.     else
  1211.     {
  1212.         if (bPMesh)
  1213.             cFacesNew = m_pmcSelectedMesh->pPMMesh->GetNumFaces();
  1214.         else
  1215.             cFacesNew = m_pmcSelectedMesh->pSimpMesh->GetNumFaces();
  1216.  
  1217.         if (cFacesChange + (int)cFacesNew < 1)
  1218.             cFacesNew = 1;
  1219.         else
  1220.             cFacesNew += cFacesChange;
  1221.     }
  1222.  
  1223.     if (bPMesh)
  1224.     {
  1225.         m_pmcSelectedMesh->pPMMesh->SetNumFaces(cFacesNew);
  1226.  
  1227.         DWORD cVertices = m_pmcSelectedMesh->pPMMesh->GetNumVertices();
  1228.         if (cVertices < m_pmcSelectedMesh->m_cMinVerticesSoft)
  1229.             m_pmcSelectedMesh->pPMMesh->SetNumVertices(m_pmcSelectedMesh->m_cMinVerticesSoft);
  1230.         if (cVertices > m_pmcSelectedMesh->m_cMaxVerticesSoft)
  1231.             m_pmcSelectedMesh->pPMMesh->SetNumVertices(m_pmcSelectedMesh->m_cMaxVerticesSoft);
  1232.     }
  1233.     else
  1234.         m_pmcSelectedMesh->pSimpMesh->ReduceFaces(cFacesNew);
  1235.  
  1236.  
  1237.     if (bSimpMesh)
  1238.     {
  1239.         GXRELEASE(m_pmcSelectedMesh->pMesh);
  1240.  
  1241.         // make a drawable image of the current simplification mesh
  1242.         m_pmcSelectedMesh->pSimpMesh->CloneMesh(m_pmcSelectedMesh->pSimpMesh->GetOptions(),
  1243.                                         NULL, 
  1244.                                         m_pDevice, NULL, NULL, &m_pmcSelectedMesh->pMesh);
  1245.  
  1246.         m_pmcSelectedMesh->ptmDrawMesh = m_pmcSelectedMesh->pMesh;
  1247.         m_pmcSelectedMesh->pMesh->AddRef();
  1248.     }
  1249.  
  1250.     m_pmcSelectedMesh->ptmDrawMesh->GetAttributeTable(m_pmcSelectedMesh->m_rgaeAttributeTable, NULL);
  1251.  
  1252.     AdjustScrollbar();
  1253. }
  1254.  
  1255. // control window to work with per vertex component weight inputs
  1256. LRESULT CALLBACK
  1257. DlgProcSimplifyInputs(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  1258. {
  1259.     WORD nId = 0, nNotifyCode = 0;
  1260.     char szBuf[1024];
  1261.     char *pTmp;
  1262.     HRESULT hr;
  1263.     LPD3DXATTRIBUTEWEIGHTS pAttributeWeights = (LPD3DXATTRIBUTEWEIGHTS)g_pData->pvDialogData;
  1264.  
  1265.     GXASSERT(pAttributeWeights != NULL);
  1266.  
  1267.     switch (message)
  1268.     {
  1269.     case WM_SETFONT:
  1270.         return TRUE;
  1271.  
  1272.     case WM_INITDIALOG:
  1273.         sprintf(szBuf, "%f", pAttributeWeights->Position);
  1274.         SetDlgItemText(hDlg, IDC_POSITIONWEIGHT, szBuf);
  1275.  
  1276.         sprintf(szBuf, "%f", pAttributeWeights->Boundary);
  1277.         SetDlgItemText(hDlg, IDC_BOUNDARYWEIGHT, szBuf);
  1278.  
  1279.         sprintf(szBuf, "%f", pAttributeWeights->Normal);
  1280.         SetDlgItemText(hDlg, IDC_NORMALWEIGHT, szBuf);
  1281.  
  1282.         sprintf(szBuf, "%f", pAttributeWeights->Diffuse);
  1283.         SetDlgItemText(hDlg, IDC_DIFFUSEWEIGHT, szBuf);
  1284.  
  1285.         sprintf(szBuf, "%f", pAttributeWeights->Specular);
  1286.         SetDlgItemText(hDlg, IDC_SPECULARWEIGHT, szBuf);
  1287.  
  1288.         sprintf(szBuf, "%f", pAttributeWeights->Texcoord[0]);
  1289.         SetDlgItemText(hDlg, IDC_TEXTUREWEIGHT, szBuf);
  1290.  
  1291.         return TRUE;
  1292.  
  1293.     case WM_COMMAND:
  1294.         nId = LOWORD(wParam);
  1295.         nNotifyCode = HIWORD(wParam);
  1296.         switch (nId)
  1297.         {
  1298.         case IDOK:
  1299.             memset(pAttributeWeights, 0, sizeof(D3DXATTRIBUTEWEIGHTS));
  1300.  
  1301.             GetDlgItemText(hDlg, IDC_POSITIONWEIGHT, szBuf, 256);
  1302.             pAttributeWeights->Position = (float)strtod(szBuf, &pTmp);
  1303.             if (pTmp && (*pTmp != '\0'))
  1304.                 goto e_Exit;
  1305.  
  1306.             GetDlgItemText(hDlg, IDC_BOUNDARYWEIGHT, szBuf, 256);
  1307.             pAttributeWeights->Boundary = (float)strtod(szBuf, &pTmp);
  1308.             if (pTmp && (*pTmp != '\0'))
  1309.                 goto e_Exit;
  1310.  
  1311.             GetDlgItemText(hDlg, IDC_NORMALWEIGHT, szBuf, 256);
  1312.             pAttributeWeights->Normal = (float)strtod(szBuf, &pTmp);
  1313.             if (pTmp && (*pTmp != '\0'))
  1314.                 goto e_Exit;
  1315.  
  1316.             GetDlgItemText(hDlg, IDC_DIFFUSEWEIGHT, szBuf, 256);
  1317.             pAttributeWeights->Diffuse = (float)strtod(szBuf, &pTmp);
  1318.             if (pTmp && (*pTmp != '\0'))
  1319.                 goto e_Exit;
  1320.  
  1321.             GetDlgItemText(hDlg, IDC_SPECULARWEIGHT, szBuf, 256);
  1322.             pAttributeWeights->Specular = (float)strtod(szBuf, &pTmp);
  1323.             if (pTmp && (*pTmp != '\0'))
  1324.                 goto e_Exit;
  1325.  
  1326.             GetDlgItemText(hDlg, IDC_TEXTUREWEIGHT, szBuf, 256);
  1327.             pAttributeWeights->Texcoord[0] = (float)strtod(szBuf, &pTmp);
  1328.             if (pTmp && (*pTmp != '\0'))
  1329.                 goto e_Exit;
  1330.  
  1331.             // set all texture weights to the same value
  1332.             pAttributeWeights->Texcoord[1] = pAttributeWeights->Texcoord[0];
  1333.             pAttributeWeights->Texcoord[2] = pAttributeWeights->Texcoord[3] = pAttributeWeights->Texcoord[0];
  1334.             pAttributeWeights->Texcoord[4] = pAttributeWeights->Texcoord[5] = pAttributeWeights->Texcoord[0];
  1335.             pAttributeWeights->Texcoord[6] = pAttributeWeights->Texcoord[7] = pAttributeWeights->Texcoord[0];
  1336.  
  1337.             if (nId == IDOK)
  1338.             {
  1339.                 EndDialog(hDlg, 0);
  1340.             }
  1341.  
  1342.             return TRUE;
  1343.         case IDCANCEL:
  1344.             EndDialog(hDlg, 1);
  1345.             return TRUE;
  1346.         }
  1347.         break;
  1348.     }
  1349.     return FALSE;
  1350.  
  1351. e_Exit:
  1352.     MessageBox(NULL, "Please enter a valid number", "Simplify", MB_SYSTEMMODAL | MB_OK );
  1353.     return TRUE;
  1354. }
  1355.  
  1356. HRESULT 
  1357. TrivialData::ConvertMeshToSimplify()
  1358. {
  1359.     HRESULT hr = S_OK;
  1360.     LPD3DXMESH pMeshFixed;
  1361.     D3DXATTRIBUTEWEIGHTS AttributeWeights;
  1362.     INT_PTR dwRet;
  1363.  
  1364.     ID3DXSPMesh *ptmSimplifyMeshNew = NULL;
  1365.  
  1366.     GXASSERT(!m_pmcSelectedMesh->bSimplifyMode && !m_pmcSelectedMesh->bPMMeshMode);
  1367.  
  1368.     memset(&AttributeWeights, 0, sizeof(AttributeWeights));
  1369.     AttributeWeights.Position = 1.0f;
  1370.     AttributeWeights.Boundary = 1.0f;
  1371.     AttributeWeights.Normal = 1.0f;
  1372.  
  1373.     // first figure out the AttributeWeights
  1374.     pvDialogData = &AttributeWeights;
  1375.     dwRet = DialogBox(m_hInstance, (LPCTSTR) IDD_SIMPLIFYINPUTS, m_hwnd, (DLGPROC) DlgProcSimplifyInputs);
  1376.     if (dwRet != 0)
  1377.     {
  1378.         hr = E_FAIL;
  1379.         goto e_Exit;
  1380.     }
  1381.  
  1382.     // cleanup the mesh before simplification
  1383.     CleanMesh();
  1384.  
  1385.     hr = D3DXCreateSPMesh(m_pmcSelectedMesh->pMesh, m_pmcSelectedMesh->rgdwAdjacency, &AttributeWeights, NULL, &ptmSimplifyMeshNew);
  1386.     if (FAILED(hr))
  1387.         goto e_Exit;
  1388.  
  1389.     // once successful, then set the simplification mesh as the one to draw
  1390.  
  1391.     GXRELEASE(m_pmcSelectedMesh->ptmDrawMesh);
  1392.     GXRELEASE(m_pmcSelectedMesh->pPMMesh);
  1393.     GXRELEASE(m_pmcSelectedMesh->pMesh);
  1394.  
  1395.     m_pmcSelectedMesh->pSimpMesh = ptmSimplifyMeshNew;
  1396.     ptmSimplifyMeshNew = NULL;
  1397.  
  1398.     //hr = m_pmcSelectedMesh->pPMMesh->QueryInterface(IID_IGXTri3DrawMesh, (PVOID*)&m_pmcSelectedMesh->ptmDrawMesh);
  1399.     //if (FAILED(hr))
  1400.         //goto e_Exit;
  1401.         
  1402.     m_pmcSelectedMesh->bPMMeshMode = false;
  1403.     m_pmcSelectedMesh->bSimplifyMode = true;
  1404.  
  1405.     // the maximum number of vertices changes for a simplification mesh, so
  1406.     //    remember it now so that we can give the user an idea of how far they
  1407.     //    have gone on the scrollbar
  1408.     //hr = m_pmcSelectedMesh->pPMMesh->GetMaxVertices(&m_pmcSelectedMesh->m_cMaxVertices);
  1409.     //if (FAILED(hr))
  1410.         //goto e_Exit;
  1411.  
  1412.     //hr = m_pmcSelectedMesh->pPMMesh->GetMinVertices(&m_pmcSelectedMesh->m_cMinVertices);
  1413.     //if (FAILED(hr))
  1414.         //goto e_Exit;
  1415.  
  1416.     //AdjustScrollbar();
  1417.  
  1418.     // make a drawable image of the current simplification mesh
  1419.     m_pmcSelectedMesh->pSimpMesh->CloneMesh(m_pmcSelectedMesh->pSimpMesh->GetOptions(),
  1420.                                     NULL, 
  1421.                                     m_pDevice, NULL, NULL, &m_pmcSelectedMesh->pMesh);
  1422.  
  1423.     m_pmcSelectedMesh->ptmDrawMesh = m_pmcSelectedMesh->pMesh;
  1424.     m_pmcSelectedMesh->pMesh->AddRef();
  1425.  
  1426. e_Exit:
  1427.     GXRELEASE(ptmSimplifyMeshNew);
  1428.  
  1429.     return hr;
  1430. }
  1431.  
  1432.  
  1433. // simplify the mesh as far as it will go, and then generate a PM
  1434. HRESULT 
  1435. TrivialData::GeneratePM()
  1436. {
  1437.     HRESULT hr = S_OK;
  1438.     ID3DXPMesh *pPMeshTemp;
  1439.  
  1440.     // if not in simplification mode yet, then switch to it
  1441.     if (!m_pmcSelectedMesh->bSimplifyMode)
  1442.     {
  1443.         hr = ConvertMeshToSimplify();
  1444.         if (FAILED(hr))
  1445.             goto e_Exit;
  1446.     }
  1447.  
  1448.     // simplify the mesh
  1449.     hr = m_pmcSelectedMesh->pSimpMesh->ReduceVertices(1);
  1450.     if (FAILED(hr))
  1451.         goto e_Exit;
  1452.  
  1453.     // actually generate the pSimpMesh
  1454.     hr = m_pmcSelectedMesh->pSimpMesh->ClonePMesh(
  1455.                         m_pmcSelectedMesh->pSimpMesh->GetOptions(), 
  1456.                         NULL,
  1457.                         m_pDevice,
  1458.                         NULL, NULL, &pPMeshTemp);
  1459.     if (FAILED(hr))
  1460.         goto e_Exit;
  1461.  
  1462.     GXRELEASE(m_pmcSelectedMesh->pMesh);
  1463.     GXRELEASE(m_pmcSelectedMesh->ptmDrawMesh);
  1464.     GXRELEASE(m_pmcSelectedMesh->pPMMesh);
  1465.     GXRELEASE(m_pmcSelectedMesh->pSimpMesh);
  1466.  
  1467.     m_pmcSelectedMesh->pPMMesh = pPMeshTemp; 
  1468.     
  1469.     m_pmcSelectedMesh->ptmDrawMesh = pPMeshTemp;
  1470.     pPMeshTemp->AddRef();
  1471.  
  1472.     m_pmcSelectedMesh->bPMMeshMode = true;
  1473.     m_pmcSelectedMesh->bSimplifyMode = false;
  1474.  
  1475.     m_dwFaceSelected = UNUSED32;
  1476.     m_dwVertexSelected = UNUSED32;
  1477.     UpdateSelectionInfo();
  1478.  
  1479.     m_pmcSelectedMesh->m_cNumVertices = pPMeshTemp->GetNumVertices();
  1480.     m_pmcSelectedMesh->m_cMaxVerticesSoft = pPMeshTemp->GetMaxVertices();
  1481.     m_pmcSelectedMesh->m_cMinVerticesSoft = pPMeshTemp->GetMinVertices();
  1482.  
  1483.     // update the attribute table
  1484.     m_pmcSelectedMesh->ptmDrawMesh->GetAttributeTable(m_pmcSelectedMesh->m_rgaeAttributeTable, NULL);
  1485.  
  1486.     m_pmcSelectedMesh->pPMMesh->GetAdjacency(m_pmcSelectedMesh->rgdwAdjacency);
  1487.     m_pmcSelectedMesh->UpdateViews(m_pdeSelected);
  1488.  
  1489.     // setup the scroll bar for the PM
  1490.     AdjustScrollbar();
  1491.  
  1492. e_Exit:
  1493.     return hr;
  1494. }
  1495.  
  1496.  
  1497. // simplify the mesh as far as it will go, and then generate a PM
  1498. HRESULT 
  1499. TrivialData::RemoveBackToBackTris()
  1500. {
  1501.     HRESULT hr = S_OK;
  1502.     DWORD iFace;
  1503.     DWORD cFaces;
  1504.     WORD *pwFaces = NULL;
  1505.     LPD3DXMESH pMeshFixed;
  1506.     DWORD iFaceBad;
  1507.     DWORD iAdjFace;
  1508.     DWORD iPoint;
  1509.     DWORD iPointInner;
  1510.     DWORD *rgdwAdjacency;
  1511.     DWORD cFacesRemoved = 0;
  1512.     char szBuf[80];
  1513.  
  1514.     if ((m_pmcSelectedMesh != NULL) && (m_pmcSelectedMesh->pMesh != NULL))
  1515.     {
  1516.         // not setup to handle 32bit meshes
  1517.         if (m_pmcSelectedMesh->pMesh->GetOptions() & D3DXMESH_32BIT)
  1518.         {
  1519.             hr = E_NOTIMPL;
  1520.             goto e_Exit;
  1521.         }
  1522.  
  1523.         hr = m_pmcSelectedMesh->pMesh->LockIndexBuffer(0, (LPVOID*)&pwFaces);
  1524.         if (FAILED(hr))
  1525.             goto e_Exit;
  1526.  
  1527.         cFaces = m_pmcSelectedMesh->pMesh->GetNumFaces();
  1528.         rgdwAdjacency = m_pmcSelectedMesh->rgdwAdjacency;
  1529.         for (iFace = 0; iFace < cFaces; iFace++)
  1530.         {
  1531.             if (((rgdwAdjacency[iFace*3 + 0] == rgdwAdjacency[iFace*3 + 1]) && (rgdwAdjacency[iFace*3 + 0] != UNUSED32))
  1532.                 || ((rgdwAdjacency[iFace*3 + 0] == rgdwAdjacency[iFace*3 + 2]) && (rgdwAdjacency[iFace*3 + 0] != UNUSED32))
  1533.                 || ((rgdwAdjacency[iFace*3 + 1] == rgdwAdjacency[iFace*3 + 2]) && (rgdwAdjacency[iFace*3 + 1] != UNUSED32)))
  1534.             {
  1535.                 if ((rgdwAdjacency[iFace*3 + 0] == rgdwAdjacency[iFace*3 + 1]) && (rgdwAdjacency[iFace*3 + 0] != UNUSED32))
  1536.                     iFaceBad = rgdwAdjacency[iFace*3 + 0];
  1537.                 else if ((rgdwAdjacency[iFace*3 + 0] == rgdwAdjacency[iFace*3 + 2]) && (rgdwAdjacency[iFace*3 + 0] != UNUSED32))
  1538.                     iFaceBad = rgdwAdjacency[iFace*3 + 0];
  1539.                 else // if  ((rgdwAdjacency[iFace*3 + 1] == rgdwAdjacency[iFace*3 + 2]) && (rgdwAdjacency[iFace*3 + 1] != UNUSED32)))
  1540.                     iFaceBad = rgdwAdjacency[iFace*3 + 1];
  1541.  
  1542.                 for (iPoint = 0; iPoint < 3; iPoint++)
  1543.                 {
  1544.                     iAdjFace = rgdwAdjacency[iFaceBad*3 +iPoint];
  1545.  
  1546.                     pwFaces[iFaceBad*3 +iPoint] = UNUSED16;
  1547.                     rgdwAdjacency[iFaceBad*3 +iPoint] = UNUSED32;
  1548.  
  1549.                     for (iPointInner = 0; iPointInner < 3; iPointInner++)
  1550.                     {
  1551.                         if (rgdwAdjacency[iAdjFace*3 + iPointInner] == iFaceBad)
  1552.                         {
  1553.                             rgdwAdjacency[iAdjFace*3 + iPointInner] = UNUSED32;
  1554.                         }
  1555.                     }
  1556.                 }
  1557.  
  1558.                 cFacesRemoved += 1;
  1559.             }
  1560.         }
  1561.  
  1562.         Optimize(D3DXMESHOPT_ATTRSORT);
  1563.  
  1564.         sprintf(szBuf, "Removed %d back to back tris\n", cFacesRemoved);
  1565.         OutputDebugString(szBuf);
  1566.     }
  1567.  
  1568. e_Exit:
  1569.     if (pwFaces != NULL)
  1570.     {
  1571.         m_pmcSelectedMesh->pMesh->UnlockIndexBuffer();
  1572.     }
  1573.  
  1574.     return hr;
  1575. }
  1576.  
  1577. HRESULT
  1578. TrivialData::RemoveAllMeshesExceptSelectedFromFrame(SFrame *pframeCur)
  1579. {
  1580.     HRESULT hr = S_OK;
  1581.     SMeshContainer *pmcMesh;
  1582.     SFrame *pframeChild;
  1583.  
  1584.     if ((pframeCur->pmcMesh != NULL) && (pframeCur->pmcMesh != m_pmcSelectedMesh))
  1585.     {
  1586.         delete pframeCur->pmcMesh;
  1587.         pframeCur->pmcMesh = NULL;
  1588.     }
  1589.  
  1590.     pframeChild = pframeCur->pframeFirstChild;
  1591.     while (pframeChild != NULL)
  1592.     {
  1593.         hr = RemoveAllMeshesExceptSelectedFromFrame(pframeChild);
  1594.         if (FAILED(hr))
  1595.             return hr;
  1596.  
  1597.         pframeChild = pframeChild->pframeSibling;
  1598.     }
  1599.  
  1600.     return S_OK;
  1601. }
  1602.  
  1603. HRESULT 
  1604. TrivialData::RemoveAllMeshesExceptSelected()
  1605. {
  1606.     SDrawElement *pdeCur;
  1607.     HRESULT hr = S_OK;
  1608.  
  1609.     pdeCur = m_pdeHead;
  1610.     while (pdeCur != NULL)
  1611.     {
  1612.         hr = RemoveAllMeshesExceptSelectedFromFrame(pdeCur->pframeRoot);
  1613.         if (FAILED(hr))
  1614.             return hr;
  1615.  
  1616.         pdeCur = pdeCur->pdeNext;
  1617.     }
  1618.  
  1619.     return S_OK;
  1620. }
  1621.  
  1622. template <class UINT_IDX, unsigned int UNUSED>
  1623. class CFIFOIndexCacheQueue
  1624. {
  1625. public:
  1626.     CFIFOIndexCacheQueue(UINT cMaxElements)
  1627.         :m_rgiQueue(NULL), m_cElementsMax(cMaxElements) {}
  1628.  
  1629.     ~CFIFOIndexCacheQueue()
  1630.         {
  1631.             delete []m_rgiQueue;
  1632.         }
  1633.  
  1634.     HRESULT Init()
  1635.     {
  1636.         UINT iElement;
  1637.  
  1638.         if (m_rgiQueue == NULL)
  1639.         {
  1640.             m_rgiQueue = new UINT_IDX[m_cElementsMax];
  1641.             if (m_rgiQueue == NULL)
  1642.                 return E_OUTOFMEMORY;
  1643.         }
  1644.  
  1645.         for (iElement = 0; iElement < m_cElementsMax; iElement++)
  1646.         {
  1647.             m_rgiQueue[iElement] = UNUSED;
  1648.         }
  1649.  
  1650.         m_cElements = 0;
  1651.         m_iNextElement = 0;
  1652.         m_iHead = 0;
  1653.  
  1654.         return S_OK;
  1655.     }
  1656.  
  1657.     bool BElementPresent(UINT_IDX iElementTest)
  1658.     {
  1659.         UINT iElement;
  1660.  
  1661.         for (iElement = 0; iElement < m_cElementsMax; iElement++)
  1662.         {
  1663.             if (m_rgiQueue[iElement] == iElementTest)
  1664.                 return true;
  1665.         }
  1666.  
  1667.         return false;
  1668.     }
  1669.  
  1670.     void InsertElement(UINT_IDX iElementNew)
  1671.     {
  1672.         m_rgiQueue[m_iNextElement] = iElementNew;
  1673.  
  1674.         m_cElements += 1;
  1675.  
  1676.         m_iNextElement = m_iNextElement + 1;
  1677.         if (m_iNextElement == m_cElementsMax)
  1678.             m_iNextElement = 0;
  1679.     }
  1680.  
  1681. private:
  1682.     UINT m_iHead;
  1683.     UINT m_iNextElement;
  1684.     UINT m_cElements;
  1685.     UINT m_cElementsMax;
  1686.  
  1687.     UINT_IDX *m_rgiQueue;
  1688. };
  1689.  
  1690. template <class UINT_IDX, unsigned int UNUSED>
  1691. class CFIFOVertexCache
  1692. {
  1693. public:
  1694.     CFIFOVertexCache(UINT cVertexCacheSize): m_iqCache(cVertexCacheSize) {}
  1695.  
  1696.     HRESULT Clear()
  1697.     {
  1698.         return m_iqCache.Init();
  1699.     }
  1700.  
  1701.     // mark as using the vertex, if in the cache set bHit to true, else
  1702.     //   just add to the cache
  1703.     void AccessVertex(UINT_IDX iVertex, bool &bHit)
  1704.     {
  1705.         GXASSERT(iVertex != UNUSED);
  1706.  
  1707.         bHit = m_iqCache.BElementPresent(iVertex);
  1708.         if (!bHit)
  1709.         {
  1710.             m_iqCache.InsertElement(iVertex);
  1711.         }
  1712.     }
  1713.  
  1714. private:
  1715.     CFIFOIndexCacheQueue<UINT_IDX,UNUSED> m_iqCache;
  1716. };
  1717.  
  1718. template <class UINT_IDX, unsigned int UNUSED>
  1719. class CLRUIndexCacheQueue
  1720. {
  1721. public:
  1722.     CLRUIndexCacheQueue(UINT cMaxElements)
  1723.         :m_rgiQueue(NULL), m_rgiEntryTime(NULL), m_cElementsMax(cMaxElements) {}
  1724.  
  1725.     ~CLRUIndexCacheQueue()
  1726.         {
  1727.             delete []m_rgiQueue;
  1728.             delete []m_rgiEntryTime;
  1729.         }
  1730.  
  1731.     HRESULT Init()
  1732.     {
  1733.         UINT iElement;
  1734.  
  1735.         if (m_rgiQueue == NULL)
  1736.         {
  1737.             m_rgiQueue = new UINT_IDX[m_cElementsMax];
  1738.             m_rgiEntryTime = new DWORD[m_cElementsMax];
  1739.             if ((m_rgiQueue == NULL) || (m_rgiEntryTime == NULL))
  1740.                 return E_OUTOFMEMORY;
  1741.         }
  1742.  
  1743.         for (iElement = 0; iElement < m_cElementsMax; iElement++)
  1744.         {
  1745.             m_rgiQueue[iElement] = UNUSED;
  1746.             m_rgiEntryTime[iElement] = 0;
  1747.         }
  1748.  
  1749.         m_iCurTime = 0;
  1750.  
  1751.         return S_OK;
  1752.     }
  1753.  
  1754.     bool BElementPresent(UINT_IDX iElementTest)
  1755.     {
  1756.         UINT iElement;
  1757.  
  1758.         for (iElement = 0; iElement < m_cElementsMax; iElement++)
  1759.         {
  1760.             if (m_rgiQueue[iElement] == iElementTest)
  1761.             {
  1762.                 m_iCurTime += 1;
  1763.                 m_rgiEntryTime[iElement] = m_iCurTime;
  1764.                 return true;
  1765.             }
  1766.         }
  1767.  
  1768.         return false;
  1769.     }
  1770.  
  1771.     void InsertElement(UINT_IDX iElementNew)
  1772.     {
  1773.         UINT iElement;
  1774.         UINT iFoundElement = UNUSED32;
  1775.         UINT iFoundTime = UNUSED32;
  1776.  
  1777.         for (iElement = 0; iElement < m_cElementsMax; iElement++)
  1778.         {
  1779.             if (m_rgiQueue[iElement] == UNUSED)
  1780.             {
  1781.                 iFoundElement = iElement;
  1782.                 break;
  1783.             }
  1784.             else if (iFoundTime > m_rgiEntryTime[iElement])
  1785.             {
  1786.                 iFoundTime = m_rgiEntryTime[iElement];
  1787.                 iFoundElement = iElement;
  1788.             }
  1789.         }
  1790.         GXASSERT(iFoundElement <= m_cElementsMax);
  1791.  
  1792.         m_iCurTime += 1;
  1793.         m_rgiQueue[iFoundElement] = iElementNew;
  1794.         m_rgiEntryTime[iFoundElement] = m_iCurTime;
  1795.     }
  1796.  
  1797. private:
  1798.     UINT m_cElementsMax;
  1799.     DWORD m_iCurTime;
  1800.  
  1801.     UINT_IDX *m_rgiQueue;
  1802.     DWORD *m_rgiEntryTime;
  1803.  
  1804. };
  1805.  
  1806. template <class UINT_IDX, unsigned int UNUSED>
  1807. class CLRUVertexCache
  1808. {
  1809. public:
  1810.     CLRUVertexCache(UINT cVertexCacheSize): m_iqCache(cVertexCacheSize) {}
  1811.  
  1812.     HRESULT Clear()
  1813.     {
  1814.         return m_iqCache.Init();
  1815.     }
  1816.  
  1817.     // mark as using the vertex, if in the cache set bHit to true, else
  1818.     //   just add to the cache
  1819.     void AccessVertex(UINT_IDX iVertex, bool &bHit)
  1820.     {
  1821.         GXASSERT(iVertex != UNUSED);
  1822.  
  1823.         bHit = m_iqCache.BElementPresent(iVertex);
  1824.         if (!bHit)
  1825.         {
  1826.             m_iqCache.InsertElement(iVertex);
  1827.         }
  1828.     }
  1829.  
  1830. private:
  1831.     CLRUIndexCacheQueue<UINT_IDX,UNUSED> m_iqCache;
  1832. };
  1833.  
  1834. template<class UINT_IDX, unsigned int UNUSED>
  1835. HRESULT
  1836. SimulateCache(DWORD iVertexCacheSize, LPD3DXMESH pMesh, BOOL bLRU, char szBuf[80], UINT_IDX Dummy)
  1837. {
  1838.     HRESULT hr = S_OK;
  1839.     CFIFOVertexCache<UINT_IDX, UNUSED> svcFIFO(iVertexCacheSize);
  1840.     CLRUVertexCache<UINT_IDX, UNUSED> svcLRU(iVertexCacheSize);
  1841.     UINT iIndex;
  1842.     UINT cIndices;
  1843.     UINT iPoint;
  1844.     UINT_IDX *pwFaces;
  1845.     UINT cMisses;
  1846.     bool bHit;
  1847.  
  1848.     hr = svcFIFO.Clear();
  1849.     if (FAILED(hr))
  1850.         goto e_Exit;
  1851.     hr = svcLRU.Clear();
  1852.     if (FAILED(hr))
  1853.         goto e_Exit;
  1854.  
  1855.     hr = pMesh->LockIndexBuffer(0, (LPVOID*)&pwFaces);
  1856.     if (FAILED(hr))
  1857.         goto e_Exit;
  1858.  
  1859.     cIndices = pMesh->GetNumFaces() * 3;
  1860.  
  1861.     cMisses = 0;
  1862.     for (iIndex = 0; iIndex < cIndices; iIndex++)
  1863.     {
  1864.         if (bLRU)
  1865.             svcLRU.AccessVertex(pwFaces[iIndex], bHit);
  1866.         else
  1867.             svcFIFO.AccessVertex(pwFaces[iIndex], bHit);
  1868.  
  1869.         cMisses += !bHit;
  1870.     }
  1871.  
  1872.     pMesh->UnlockIndexBuffer();
  1873.  
  1874.     if (bLRU)
  1875.         sprintf(szBuf, "LRU  Cache Size: %d, Misses: %d, Miss Rate: %f\r\n", iVertexCacheSize, cMisses, (float)cMisses / (float)pMesh->GetNumVertices());
  1876.     else
  1877.         sprintf(szBuf, "FIFO Cache Size: %d, Misses: %d, Miss Rate: %f\r\n", iVertexCacheSize, cMisses, (float)cMisses / (float)pMesh->GetNumVertices());
  1878.  
  1879. e_Exit:
  1880.     return hr;
  1881. }
  1882.  
  1883. HRESULT
  1884. GenerateCacheInfo(LPD3DXMESH pMesh, char **pszBuffer)
  1885. {
  1886.     HRESULT hr = S_OK;
  1887.     char szBuf[120];
  1888.     const DWORD x_iMaxCacheSize = 16;
  1889.     const DWORD x_iMinCacheSize = 3;
  1890.     const DWORD x_cCacheSizes = x_iMaxCacheSize - x_iMinCacheSize + 1;
  1891.     UINT16 Dummy16 = 0;
  1892.     UINT32 Dummy32 = 0;
  1893.     BOOL b16BitMesh = FALSE;
  1894.     DWORD iCacheSize;
  1895.  
  1896.     char *szOutput = NULL;
  1897.  
  1898.     GXASSERT(pMesh != NULL);
  1899.     GXASSERT(pszBuffer != NULL);
  1900.  
  1901.     b16BitMesh = !(pMesh->GetOptions() & D3DXMESH_32BIT);
  1902.  
  1903.     szOutput = new char[120 * (x_cCacheSizes*2 + 2)];
  1904.     if (szOutput == NULL)
  1905.     {
  1906.         hr = E_OUTOFMEMORY;
  1907.         goto e_Exit;
  1908.     }
  1909.  
  1910.     sprintf(szOutput, "Miss rates for using optimized mesh with FIFO caches (Mesh optimized for %d entries)\r\n",12);
  1911.     for (iCacheSize = x_iMaxCacheSize; iCacheSize >= x_iMinCacheSize; iCacheSize--)
  1912.     {
  1913.         if (b16BitMesh)
  1914.             SimulateCache<UINT16,UNUSED16>(iCacheSize, pMesh, FALSE /*FIFO*/, szBuf, Dummy16);
  1915.         else
  1916.             SimulateCache<UINT32,UNUSED32>(iCacheSize, pMesh, FALSE /*FIFO*/, szBuf, Dummy32);
  1917.  
  1918.         strcat(szOutput, szBuf);
  1919.     }
  1920.  
  1921.  
  1922.     sprintf(szBuf, "\r\nMiss rates for using optimized mesh with LRU caches (Mesh optimized for %d entries)\r\n",12);
  1923.     strcat(szOutput, szBuf);
  1924.  
  1925.     for (iCacheSize = x_iMaxCacheSize; iCacheSize >= x_iMinCacheSize; iCacheSize--)
  1926.     {
  1927.         if (b16BitMesh)
  1928.             SimulateCache<UINT16,UNUSED16>(iCacheSize, pMesh, TRUE /*LRU*/, szBuf, Dummy16);
  1929.         else
  1930.             SimulateCache<UINT32,UNUSED32>(iCacheSize, pMesh, TRUE /*LRU*/, szBuf, Dummy32);
  1931.  
  1932.         strcat(szOutput, szBuf);
  1933.     }
  1934.  
  1935.     *pszBuffer = szOutput;
  1936.     szOutput = NULL;
  1937.  
  1938. e_Exit:
  1939.     delete []szOutput;
  1940.     return hr;
  1941. }
  1942.  
  1943. HRESULT 
  1944. TrivialData::SimulateCacheStuff()
  1945. {
  1946.     DWORD iHWVertexCacheSize;
  1947.     DWORD iOptVertexCacheSize;
  1948.     BOOL b16BitMesh;
  1949.     UINT32 Dummy32 = 0;
  1950.     UINT16 Dummy16 = 0;
  1951.     char szBuf[120];
  1952.     char *szOutput = NULL;
  1953.     HRESULT hr;
  1954.     LPD3DXMESH pMeshTemp;
  1955.     const DWORD x_iOptMaxCacheSize = 16;
  1956.     const DWORD x_iOptMinCacheSize = 3;
  1957.     const DWORD x_cOptCacheSizes = x_iOptMaxCacheSize - x_iOptMinCacheSize + 1;
  1958.     const DWORD x_iHWMaxCacheSize = 16;
  1959.     const DWORD x_iHWMinCacheSize = 3;
  1960.     const DWORD x_cHWCacheSizes = x_iHWMaxCacheSize - x_iHWMinCacheSize + 1;
  1961.  
  1962.  
  1963.     if ((m_pmcSelectedMesh == NULL) || m_pmcSelectedMesh->bPMMeshMode || (m_pmcSelectedMesh->pMesh == NULL))
  1964.         return S_OK;
  1965.  
  1966.     szOutput = new char[120 * ((x_cOptCacheSizes+3)*x_cHWCacheSizes*2)];
  1967.     if (szOutput == NULL)
  1968.     {
  1969.         hr = E_OUTOFMEMORY;
  1970.         goto e_Exit;
  1971.     }
  1972.     szOutput[0] = '\0';
  1973.  
  1974.     b16BitMesh = !(m_pmcSelectedMesh->pMesh->GetOptions() & D3DXMESH_32BIT);
  1975.  
  1976.     //for (iOptVertexCacheSize = 18; iOptVertexCacheSize >= 10; iOptVertexCacheSize--)
  1977.     for (iOptVertexCacheSize = x_iOptMaxCacheSize; iOptVertexCacheSize >= x_iOptMinCacheSize; iOptVertexCacheSize--)
  1978.     {
  1979.         // set the vertex cache size (works in debug only)
  1980.         sprintf(szBuf, "%d", iOptVertexCacheSize);
  1981.         //sprintf(szBuf, "%d", 3);
  1982.         SetEnvironmentVariable("D3DXVertexCacheSize", szBuf);
  1983.  
  1984.         //sprintf(szBuf, "%d", iOptVertexCacheSize-1);
  1985.         //SetEnvironmentVariable("D3DXOptMagicNumber", szBuf);
  1986.  
  1987.         sprintf(szBuf, "Optimized for vertex cache of %d entries\r\n", iOptVertexCacheSize);
  1988.         strcat(szOutput, szBuf);
  1989.  
  1990.         // optimize for that size
  1991.         hr = m_pmcSelectedMesh->pMesh->Optimize(D3DXMESHOPT_VERTEXCACHE, m_pmcSelectedMesh->rgdwAdjacency, 
  1992.             NULL, NULL, NULL, &pMeshTemp);
  1993.         if (FAILED(hr))
  1994.             return hr;
  1995.  
  1996.         // first do FIFO
  1997.         sprintf(szBuf, "\r\nMiss rates for using optimized mesh with FIFO caches (Mesh optimized for %d entries)\r\n",iOptVertexCacheSize);
  1998.         strcat(szOutput, szBuf);
  1999.         for (iHWVertexCacheSize = x_iHWMaxCacheSize; iHWVertexCacheSize >= x_iHWMinCacheSize; iHWVertexCacheSize--)
  2000.         {
  2001.             if (b16BitMesh)
  2002.                 SimulateCache<UINT16,UNUSED16>(iHWVertexCacheSize, pMeshTemp, FALSE /*FIFO*/, szBuf, Dummy16);
  2003.             else
  2004.                 SimulateCache<UINT32,UNUSED32>(iHWVertexCacheSize, pMeshTemp, FALSE /*FIFO*/, szBuf, Dummy32);
  2005.             strcat(szOutput, szBuf);
  2006.         }
  2007.  
  2008.         // next do LRU
  2009.         sprintf(szBuf, "\r\nMiss rates for using optimized mesh with LRU caches (Mesh optimized for %d entries)\r\n",iOptVertexCacheSize);
  2010.         strcat(szOutput, szBuf);
  2011.         for (iHWVertexCacheSize = x_iHWMaxCacheSize; iHWVertexCacheSize >= x_iHWMinCacheSize; iHWVertexCacheSize--)
  2012.         {
  2013.             if (b16BitMesh)
  2014.                 SimulateCache<UINT16,UNUSED16>(iHWVertexCacheSize, pMeshTemp, TRUE /*LRU*/, szBuf, Dummy16);
  2015.             else
  2016.                 SimulateCache<UINT32,UNUSED32>(iHWVertexCacheSize, pMeshTemp, TRUE /*LRU*/, szBuf, Dummy32);
  2017.  
  2018.             strcat(szOutput, szBuf);
  2019.         }
  2020.  
  2021.         strcat(szOutput, "\r\n");
  2022.  
  2023.         GXRELEASE(pMeshTemp);
  2024.     }
  2025.  
  2026.     // display info
  2027.     pvDialogData = (PVOID)szOutput;
  2028.     DialogBox(m_hInstance, (LPCTSTR) IDD_INFO, m_hwnd, (DLGPROC) DlgProcOutput);
  2029.  
  2030.  
  2031. e_Exit:
  2032.     delete []szOutput;
  2033.  
  2034.     return S_OK;
  2035. }
  2036.  
  2037.  
  2038. template<class UINT_IDX, unsigned int UNUSED>
  2039. HRESULT
  2040. BuildHistogram(LPD3DXMESH pMesh, UINT_IDX Dummy)
  2041. {
  2042.     HRESULT hr = S_OK;
  2043.     DWORD *rgdwDistances = NULL;
  2044.     DWORD *rgdwPrevIndex = NULL;
  2045.     DWORD cNonRepeatedIndices;
  2046.     DWORD cVertices;
  2047.     DWORD cFaces;
  2048.     DWORD cIndices;
  2049.     UINT_IDX *pwIndices = NULL;
  2050.     DWORD iIndex;
  2051.     DWORD wCurIndex;
  2052.     DWORD iDistance;
  2053.     char szBuf[120];
  2054.     DWORD cSum;
  2055.  
  2056.     cVertices = pMesh->GetNumVertices();
  2057.     cFaces = pMesh->GetNumFaces();
  2058.     cIndices = cFaces * 3;
  2059.  
  2060.     hr = pMesh->LockIndexBuffer(0, (LPVOID*)&pwIndices);
  2061.     if (FAILED(hr))
  2062.         goto e_Exit;
  2063.  
  2064.     rgdwPrevIndex = new DWORD[cVertices];
  2065.     rgdwDistances = new DWORD[cIndices];
  2066.     if ((rgdwDistances == NULL) || (rgdwDistances == NULL))
  2067.     {
  2068.         hr = E_OUTOFMEMORY;
  2069.         goto e_Exit;
  2070.     }
  2071.  
  2072.     memset(rgdwDistances, 0, sizeof(DWORD) * cIndices);
  2073.     memset(rgdwPrevIndex, 0xff, sizeof(DWORD) * cVertices);
  2074.  
  2075.     // first find the distances between the repeats
  2076.     for (iIndex = 0; iIndex < cIndices; iIndex++)
  2077.     {
  2078.         wCurIndex = pwIndices[iIndex];
  2079.  
  2080.         if (rgdwPrevIndex[wCurIndex] != UNUSED32)
  2081.         {
  2082.             iDistance = iIndex - rgdwPrevIndex[wCurIndex];
  2083.             rgdwDistances[iDistance] += 1;
  2084.         }
  2085.  
  2086.         rgdwPrevIndex[wCurIndex] = iIndex;
  2087.     }
  2088.  
  2089.     // next find the number of indices that only ocurred once
  2090.     cNonRepeatedIndices = cIndices;
  2091.     for (iIndex = 0; iIndex < cIndices; iIndex++)
  2092.     {
  2093.         cNonRepeatedIndices -= rgdwDistances[iIndex];
  2094.     }
  2095.  
  2096.     OutputDebugString("Cache Independent Histogram: (First n entries only)\n");
  2097.     sprintf(szBuf, "Total Indices: %d, Unique Indices: %d\n", cIndices, cNonRepeatedIndices);
  2098.     OutputDebugString(szBuf);
  2099.  
  2100.  
  2101.     OutputDebugString("Bin   Frequency\n");
  2102.     cSum = 0;
  2103.     for (iIndex = 1; iIndex < min(64, cVertices); iIndex++)
  2104.     {
  2105.         cSum += rgdwDistances[iIndex];
  2106.         sprintf(szBuf, "%d   %d    %f\n", iIndex, rgdwDistances[iIndex], (float)cSum / (float)cIndices);
  2107.         OutputDebugString(szBuf);
  2108.     }
  2109.  
  2110. e_Exit:
  2111.     delete []rgdwDistances;
  2112.     delete []rgdwPrevIndex;
  2113.  
  2114.     if (pwIndices != NULL)
  2115.     {
  2116.         pMesh->UnlockIndexBuffer();
  2117.     }
  2118.  
  2119.     return hr;
  2120. }
  2121.  
  2122. HRESULT 
  2123. TrivialData::BuildCacheHistogram()
  2124. {
  2125.     DWORD iHWVertexCacheSize;
  2126.     DWORD iOptVertexCacheSize;
  2127.     BOOL b16BitMesh;
  2128.     UINT32 Dummy32 = 0;
  2129.     UINT16 Dummy16 = 0;
  2130.     char szBuf[120];
  2131.     HRESULT hr;
  2132.     LPD3DXMESH pMeshTemp;
  2133.  
  2134.     if ((m_pmcSelectedMesh == NULL) || m_pmcSelectedMesh->bPMMeshMode || (m_pmcSelectedMesh->pMesh == NULL))
  2135.         return S_OK;
  2136.  
  2137.     b16BitMesh = !(m_pmcSelectedMesh->pMesh->GetOptions() & D3DXMESH_32BIT);
  2138.  
  2139.     //for (iOptVertexCacheSize = 18; iOptVertexCacheSize >= 10; iOptVertexCacheSize--)
  2140.     for (iOptVertexCacheSize = 12; iOptVertexCacheSize >= 12; iOptVertexCacheSize--)
  2141.     {
  2142.         // set the vertex cache size (works in debug only)
  2143.         //sprintf(szBuf, "%d", iOptVertexCacheSize);
  2144.         //sprintf(szBuf, "%d", 3);
  2145.         //SetEnvironmentVariable("D3DXVertexCacheSize", szBuf);
  2146.  
  2147.         //sprintf(szBuf, "%d", iOptVertexCacheSize-1);
  2148.         //SetEnvironmentVariable("D3DXOptMagicNumber", szBuf);
  2149.  
  2150.         sprintf(szBuf, "Optimized for vertex cache of %d entries\n", iOptVertexCacheSize);
  2151.         OutputDebugString(szBuf);
  2152.  
  2153.         // optimize for that size
  2154.         hr = m_pmcSelectedMesh->pMesh->Optimize(D3DXMESHOPT_VERTEXCACHE, m_pmcSelectedMesh->rgdwAdjacency, 
  2155.             NULL, NULL, NULL, &pMeshTemp);
  2156.         if (FAILED(hr))
  2157.             return hr;
  2158.  
  2159.         // first do FIFO
  2160.         sprintf(szBuf, "\nMiss rates for using optimized mesh with FIFO caches (Mesh optimized for %d entries)\n",iOptVertexCacheSize);
  2161.         OutputDebugString(szBuf);
  2162.  
  2163.         if (b16BitMesh)
  2164.             BuildHistogram<UINT16,UNUSED16>(pMeshTemp, Dummy16);
  2165.         else
  2166.             BuildHistogram<UINT32,UNUSED32>(pMeshTemp, Dummy32);
  2167.  
  2168.         OutputDebugString("\n");
  2169.  
  2170.         GXRELEASE(pMeshTemp);
  2171.     }
  2172.  
  2173.     return S_OK;
  2174. }
  2175.  
  2176.  
  2177. LRESULT CALLBACK
  2178. DlgProcWeldVertices(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  2179. {
  2180.     WORD nId = 0, nNotifyCode = 0;
  2181.     char szBuf[1024];
  2182.     char *pTmp;
  2183.     HRESULT hr;
  2184.     float fSkinWeightsEspilon;
  2185.     float fNormalEspilon;
  2186.     float fTextureEspilon;
  2187.     BOOL bRemoveBackToBackTris;
  2188.     BOOL bRegenerateAdjacency;
  2189.     DWORD cPreWeldVertices;
  2190.     DWORD cPostWeldVertices;
  2191.     DWORD cFacesRemoved;
  2192.     D3DXWELDEPSILONS Epsilons;
  2193.     BOOL bChangedSelInfo;
  2194.     DWORD *rgdwFaceRemap = NULL;
  2195.     LPD3DXBUFFER *ppbufVertRemapParam = NULL;
  2196.     LPD3DXBUFFER pbufVertRemap = NULL;
  2197.     DWORD dwFlags;
  2198.  
  2199.     switch (message)
  2200.     {
  2201.     case WM_SETFONT:
  2202.         return TRUE;
  2203.  
  2204.     case WM_INITDIALOG:
  2205.         SetDlgItemText(hDlg, IDC_WELDCONSOLE, "<no weld performed yet>");
  2206.  
  2207.         sprintf(szBuf, "%f", 0.01f);
  2208.         SetDlgItemText(hDlg, IDC_NORMALSEPSILON, szBuf);
  2209.  
  2210.         sprintf(szBuf, "%f", 0.01f);
  2211.         SetDlgItemText(hDlg, IDC_SKINWEIGHTSEPSILON, szBuf);
  2212.  
  2213.         sprintf(szBuf, "%f", 0.01f);
  2214.         SetDlgItemText(hDlg, IDC_TEXTUREEPSILON, szBuf);
  2215.  
  2216.         SendDlgItemMessage(hDlg, IDC_REMOVEBACKTOBACK, BM_SETCHECK, BST_UNCHECKED, 0);
  2217.         SendDlgItemMessage(hDlg, IDC_REGENERATEADJACENCY, BM_SETCHECK, BST_UNCHECKED, 0);
  2218.         SendDlgItemMessage(hDlg, IDC_PARTIALWELD, BM_SETCHECK, BST_UNCHECKED, 0);
  2219.         SendDlgItemMessage(hDlg, IDC_DONOTREMOVEVERTICES, BM_SETCHECK, BST_UNCHECKED, 0);
  2220.         SendDlgItemMessage(hDlg, IDC_WELDALLVERTICES, BM_SETCHECK, BST_UNCHECKED, 0);
  2221.         return TRUE;
  2222.  
  2223.     case WM_COMMAND:
  2224.         nId = LOWORD(wParam);
  2225.         nNotifyCode = HIWORD(wParam);
  2226.         switch (nId)
  2227.         {
  2228.         case ID_APPLY:
  2229.         case IDOK:
  2230.             GetDlgItemText(hDlg, IDC_SKINWEIGHTSEPSILON, szBuf, 256);
  2231.             fSkinWeightsEspilon = (float)strtod(szBuf, &pTmp);
  2232.             if (pTmp && (*pTmp != '\0'))
  2233.                 goto e_Exit;
  2234.  
  2235.             GetDlgItemText(hDlg, IDC_NORMALSEPSILON, szBuf, 256);
  2236.             fNormalEspilon = (float)strtod(szBuf, &pTmp);
  2237.             if (pTmp && (*pTmp != '\0'))
  2238.                 goto e_Exit;
  2239.  
  2240.             GetDlgItemText(hDlg, IDC_TEXTUREEPSILON, szBuf, 256);
  2241.             fTextureEspilon = (float)strtod(szBuf, &pTmp);
  2242.             if (pTmp && (*pTmp != '\0'))
  2243.                 goto e_Exit;
  2244.  
  2245.             memset(&Epsilons, 0, sizeof(Epsilons));
  2246.             Epsilons.Position = 1.0e-6f;
  2247.             Epsilons.Normal = fNormalEspilon;
  2248.             Epsilons.BlendWeights = fSkinWeightsEspilon;
  2249.             Epsilons.Texcoord[0] = Epsilons.Texcoord[1]  = fTextureEspilon;
  2250.             Epsilons.Texcoord[2] = Epsilons.Texcoord[3]  = fTextureEspilon;
  2251.             Epsilons.Texcoord[4] = Epsilons.Texcoord[5]  = fTextureEspilon;
  2252.             Epsilons.Texcoord[6] = Epsilons.Texcoord[7]  = fTextureEspilon;    
  2253.             dwFlags = 0;
  2254.             
  2255.             bRemoveBackToBackTris = (BST_CHECKED == SendDlgItemMessage(hDlg, IDC_REMOVEBACKTOBACK, BM_GETCHECK, 0, 0));
  2256.             bRegenerateAdjacency = (BST_CHECKED == SendDlgItemMessage(hDlg, IDC_REGENERATEADJACENCY, BM_GETCHECK, 0, 0));
  2257.  
  2258.             if (BST_CHECKED == SendDlgItemMessage(hDlg, IDC_PARTIALWELD, BM_GETCHECK, 0, 0))
  2259.                 dwFlags |= D3DXWELDEPSILONS_WELDPARTIALMATCHES;
  2260.  
  2261.             if (BST_CHECKED == SendDlgItemMessage(hDlg, IDC_DONOTREMOVEVERTICES, BM_GETCHECK, 0, 0))
  2262.                 dwFlags |= D3DXWELDEPSILONS_DONOTREMOVEVERTICES;
  2263.  
  2264.             if (BST_CHECKED == SendDlgItemMessage(hDlg, IDC_WELDALLVERTICES, BM_GETCHECK, 0, 0))
  2265.                 dwFlags |= D3DXWELDEPSILONS_WELDALL;
  2266.  
  2267.             if (bRemoveBackToBackTris)
  2268.             {
  2269.                 cFacesRemoved = g_pData->m_pmcSelectedMesh->pMesh->GetNumFaces();
  2270.                 g_pData->RemoveBackToBackTris();
  2271.                 cFacesRemoved -= g_pData->m_pmcSelectedMesh->pMesh->GetNumFaces();
  2272.             }
  2273.             else if (bRegenerateAdjacency)
  2274.             {
  2275.                 g_pData->m_pmcSelectedMesh->pMesh->GenerateAdjacency(1.0e-6f, g_pData->m_pmcSelectedMesh->rgdwAdjacency);
  2276.             }
  2277.  
  2278.             cPreWeldVertices = g_pData->m_pmcSelectedMesh->pMesh->GetNumVertices();
  2279.  
  2280.             if (g_pData->m_dwFaceSelected != UNUSED32)
  2281.             {
  2282.                 rgdwFaceRemap = new DWORD[g_pData->m_pmcSelectedMesh->pMesh->GetNumFaces()];
  2283.                 if (rgdwFaceRemap == NULL)
  2284.                 {
  2285.                     // if it failed, continue, but unselect the face/vertex
  2286.                     g_pData->m_dwFaceSelected = UNUSED32;
  2287.                     g_pData->m_dwVertexSelected = UNUSED32;
  2288.                 }
  2289.             }
  2290.  
  2291.             if (g_pData->m_dwVertexSelected != UNUSED32)
  2292.             {
  2293.                 ppbufVertRemapParam = &pbufVertRemap;
  2294.             }
  2295.  
  2296.             hr = D3DXWeldVertices(g_pData->m_pmcSelectedMesh->pMesh, dwFlags, &Epsilons,  g_pData->m_pmcSelectedMesh->rgdwAdjacency, g_pData->m_pmcSelectedMesh->rgdwAdjacency, rgdwFaceRemap, ppbufVertRemapParam);
  2297.             if (FAILED(hr))
  2298.                 goto e_Exit;
  2299.     
  2300.             if (g_pData->m_dwFaceSelected != UNUSED32)
  2301.             {
  2302.                 // if the face was moved, then find it
  2303.                 if (rgdwFaceRemap[g_pData->m_dwFaceSelected] != g_pData->m_dwFaceSelected)
  2304.                 {
  2305.                     g_pData->m_dwFaceSelected = FindDWORD(g_pData->m_dwFaceSelected, rgdwFaceRemap, g_pData->m_pmcSelectedMesh->pMesh->GetNumFaces());
  2306.  
  2307.                     bChangedSelInfo = TRUE;
  2308.                 }
  2309.             }
  2310.  
  2311.             if (g_pData->m_dwVertexSelected != UNUSED32)
  2312.             {
  2313.                 // if the face was moved, then find it
  2314.                 if (((DWORD*)(pbufVertRemap->GetBufferPointer()))[g_pData->m_dwVertexSelected] != g_pData->m_dwVertexSelected)
  2315.                 {
  2316.                     g_pData->m_dwVertexSelected = FindDWORD(g_pData->m_dwVertexSelected, 
  2317.                                             (DWORD*)(pbufVertRemap->GetBufferPointer()), 
  2318.                                             g_pData->m_pmcSelectedMesh->pMesh->GetNumVertices());
  2319.  
  2320.                     bChangedSelInfo = TRUE;
  2321.                 }
  2322.             }
  2323.  
  2324.             if (bChangedSelInfo)
  2325.             {
  2326.                 g_pData->UpdateSelectionInfo();
  2327.             }
  2328.  
  2329.             hr = g_pData->m_pmcSelectedMesh->UpdateViews(g_pData->m_pdeSelected);
  2330.             if (FAILED(hr))
  2331.                 goto e_Exit;
  2332.  
  2333.             cPostWeldVertices = g_pData->m_pmcSelectedMesh->pMesh->GetNumVertices();
  2334.  
  2335.             if (bRemoveBackToBackTris)
  2336.                 sprintf(szBuf, "Removed %d BackToBack triangles\r\nBefore weld: %d vertices\r\nAfter weld: %d vertices\r\n", cFacesRemoved, cPreWeldVertices, cPostWeldVertices);
  2337.             else
  2338.                 sprintf(szBuf, "Before weld: %d vertices\r\nAfter weld: %d vertices\r\n", cPreWeldVertices, cPostWeldVertices);
  2339.  
  2340.             SetDlgItemText(hDlg, IDC_WELDCONSOLE, szBuf);
  2341.  
  2342.  
  2343.             delete []rgdwFaceRemap;
  2344.             GXRELEASE(pbufVertRemap);
  2345.  
  2346.             if (nId == IDOK)
  2347.             {
  2348.                 EndDialog(hDlg, 0);
  2349.             }
  2350.  
  2351.             return TRUE;
  2352.         case IDCANCEL:
  2353.             EndDialog(hDlg, 1);
  2354.             return TRUE;
  2355.         }
  2356.         break;
  2357.     }
  2358.     return FALSE;
  2359.  
  2360. e_Exit:
  2361.     delete []rgdwFaceRemap;
  2362.     GXRELEASE(pbufVertRemap);
  2363.     MessageBox(NULL, "Please enter a valid number", "WeldVertices", MB_SYSTEMMODAL | MB_OK );
  2364.     return TRUE;
  2365. }
  2366.  
  2367. HRESULT 
  2368. TrivialData::WeldVertices()
  2369. {
  2370.     
  2371.     if ((m_pmcSelectedMesh == NULL) || (m_pmcSelectedMesh->pMesh == NULL))
  2372.         goto e_Exit;
  2373.  
  2374.     DialogBox(m_hInstance, (LPCTSTR) IDD_WELDVERTICES, m_hwnd, (DLGPROC) DlgProcWeldVertices);
  2375.  
  2376. e_Exit:
  2377.     return S_OK;
  2378. }
  2379.  
  2380.  
  2381. // Mesage handler for about box.
  2382. LRESULT CALLBACK 
  2383. DlgProcTestSimplify(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  2384. {
  2385.     WORD nId = 0, nNotifyCode = 0;
  2386.     char szBuf[65];
  2387.     char *pTmp;
  2388.     DWORD cTestInterval;
  2389.  
  2390.     switch (message)
  2391.     {
  2392.     case WM_INITDIALOG:
  2393.         GXASSERT(g_pData->m_pmcSelectedMesh->bSimplifyMode);
  2394.         GXASSERT(g_pData->m_pmcSelectedMesh->pSimpMesh != NULL);
  2395.  
  2396.         SetDlgItemText(hDlg, IDC_TESTINTERVAL, "10");
  2397.  
  2398.         return TRUE;
  2399.         
  2400.     case WM_COMMAND:
  2401.         nId = LOWORD(wParam);
  2402.         nNotifyCode = HIWORD(wParam);
  2403.         switch (nId)
  2404.         {
  2405.         case IDOK:
  2406.             GetDlgItemText(hDlg, IDC_TESTINTERVAL, szBuf, 256);
  2407.             cTestInterval = (long) strtoul(szBuf, &pTmp, 10);
  2408.             if (pTmp && (*pTmp != '\0'))
  2409.                 goto e_Exit;
  2410.  
  2411.             *(DWORD*)g_pData->pvDialogData = cTestInterval;
  2412.  
  2413.             EndDialog(hDlg, 0);
  2414.             return TRUE;
  2415.         case IDCANCEL:
  2416.             EndDialog(hDlg, 1);
  2417.             return TRUE;
  2418.         }
  2419.         break;
  2420.     }
  2421.     return FALSE;
  2422.  
  2423. e_Exit:
  2424.     MessageBox(NULL, "Please enter a valid number", "Simplify", MB_SYSTEMMODAL | MB_OK );
  2425.     return TRUE;
  2426. }
  2427.  
  2428. HRESULT 
  2429. TrivialData::TestSimplify()
  2430. {
  2431.     INT_PTR dwRet;
  2432.     DWORD cTestInterval = 0;
  2433.     DWORD cNumVertices;
  2434.     HRESULT hr = S_OK;
  2435.     
  2436.     if (m_pmcSelectedMesh == NULL) 
  2437.         goto e_Exit;
  2438.  
  2439.     if (!m_pmcSelectedMesh->bSimplifyMode && !m_pmcSelectedMesh->bPMMeshMode && (m_pmcSelectedMesh->pMesh != NULL))
  2440.     {
  2441.         hr = ConvertMeshToSimplify();
  2442.         if (FAILED(hr))
  2443.             goto e_Exit;
  2444.     }
  2445.  
  2446.     if ((!m_pmcSelectedMesh->bSimplifyMode) || (m_pmcSelectedMesh->pSimpMesh == NULL))
  2447.         goto e_Exit;
  2448.  
  2449.     pvDialogData = &cTestInterval;
  2450.     dwRet = DialogBox(m_hInstance, (LPCTSTR) IDD_TESTSIMPLIFY, m_hwnd, (DLGPROC) DlgProcTestSimplify);
  2451.     if (dwRet != 0)
  2452.         goto e_Exit;
  2453.     
  2454.     while (1)
  2455.     {
  2456.         cNumVertices = m_pmcSelectedMesh->pSimpMesh->GetNumVertices();
  2457.  
  2458.         hr = m_pmcSelectedMesh->pSimpMesh->ReduceVertices(cNumVertices - cTestInterval);
  2459.         if (FAILED(hr))
  2460.             goto e_Exit;
  2461.  
  2462.         AdjustScrollbar();
  2463.  
  2464.         m_pmcSelectedMesh->m_cNumVertices = m_pmcSelectedMesh->pSimpMesh->GetNumVertices();
  2465.  
  2466.         // if we hit the bottom, stop
  2467.         if (cNumVertices == m_pmcSelectedMesh->m_cNumVertices)
  2468.             break;
  2469.     }
  2470.  
  2471.     GXRELEASE(m_pmcSelectedMesh->pMesh);
  2472.  
  2473.     // make a drawable image of the current simplification mesh
  2474.     m_pmcSelectedMesh->pSimpMesh->CloneMesh(m_pmcSelectedMesh->pSimpMesh->GetOptions(),
  2475.                                     NULL, 
  2476.                                     m_pDevice, NULL, NULL, &m_pmcSelectedMesh->pMesh);
  2477.  
  2478.     m_pmcSelectedMesh->ptmDrawMesh = m_pmcSelectedMesh->pMesh;
  2479.     m_pmcSelectedMesh->pMesh->AddRef();
  2480.  
  2481. e_Exit:
  2482.     return S_OK;
  2483. }
  2484.  
  2485.  
  2486. // optimize the mesh with the given types of optimization
  2487. void 
  2488. TrivialData::Optimize(DWORD dwFlags)
  2489. {
  2490.     LPD3DXMESH pMeshNew;
  2491.     HRESULT hr;
  2492.     DWORD *pdwSwap;
  2493.     LPD3DXBUFFER *ppbufVertRemapParam = NULL;
  2494.     LPD3DXBUFFER pbufVertRemap = NULL;
  2495.     DWORD *rgdwFaceRemap = NULL;
  2496.     BOOL bChangedSelInfo = FALSE;
  2497.  
  2498.     if ((m_pmcSelectedMesh == NULL) || m_pmcSelectedMesh->bPMMeshMode || (m_pmcSelectedMesh->pMesh == NULL))
  2499.         return;
  2500.  
  2501.     if (m_dwFaceSelected != UNUSED32)
  2502.     {
  2503.         rgdwFaceRemap = new DWORD[m_pmcSelectedMesh->pMesh->GetNumFaces()];
  2504.         if (rgdwFaceRemap == NULL)
  2505.         {
  2506.             hr = E_OUTOFMEMORY;
  2507.             goto e_Exit;
  2508.         }
  2509.     }
  2510.  
  2511.     if (m_dwVertexSelected != UNUSED32)
  2512.     {
  2513.         ppbufVertRemapParam = &pbufVertRemap;
  2514.     }
  2515.  
  2516.     DWORD *rgdwAdjTemp = new DWORD[m_pmcSelectedMesh->ptmDrawMesh->GetNumFaces()*3];
  2517.     memcpy(rgdwAdjTemp, m_pmcSelectedMesh->rgdwAdjacency, sizeof(DWORD)*m_pmcSelectedMesh->ptmDrawMesh->GetNumFaces()*3);
  2518.  
  2519.     // actually perform the optimization
  2520.     hr = m_pmcSelectedMesh->pMesh->OptimizeInplace(dwFlags, m_pmcSelectedMesh->rgdwAdjacency, 
  2521.         m_pmcSelectedMesh->rgdwAdjacency, rgdwFaceRemap, ppbufVertRemapParam);
  2522.     delete []rgdwAdjTemp;
  2523.     if (FAILED(hr))
  2524.         goto e_Exit;
  2525.  
  2526.  
  2527.     if (m_dwFaceSelected != UNUSED32)
  2528.     {
  2529.         // if the face was moved, then find it
  2530.         if (rgdwFaceRemap[m_dwFaceSelected] != m_dwFaceSelected)
  2531.         {
  2532.             m_dwFaceSelected = FindDWORD(m_dwFaceSelected, rgdwFaceRemap, m_pmcSelectedMesh->pMesh->GetNumFaces());
  2533.  
  2534.             bChangedSelInfo = TRUE;
  2535.         }
  2536.     }
  2537.  
  2538.     if (m_dwVertexSelected != UNUSED32)
  2539.     {
  2540.         // if the face was moved, then find it
  2541.         if (((DWORD*)(pbufVertRemap->GetBufferPointer()))[m_dwVertexSelected] != m_dwVertexSelected)
  2542.         {
  2543.             m_dwVertexSelected = FindDWORD(m_dwVertexSelected, 
  2544.                                     (DWORD*)(pbufVertRemap->GetBufferPointer()), 
  2545.                                     m_pmcSelectedMesh->pMesh->GetNumVertices());
  2546.  
  2547.             bChangedSelInfo = TRUE;
  2548.         }
  2549.     }
  2550.  
  2551.     if (bChangedSelInfo)
  2552.     {
  2553.         UpdateSelectionInfo();
  2554.     }
  2555.  
  2556.  
  2557.     hr = m_pmcSelectedMesh->UpdateViews(m_pdeSelected);
  2558.     if (FAILED(hr))
  2559.         goto e_Exit;
  2560.  
  2561.     // if doing strip reorder or vertex cache optimization, report on cache behavior
  2562.     if (dwFlags & (D3DXMESHOPT_VERTEXCACHE|D3DXMESHOPT_STRIPREORDER))
  2563.     {
  2564.         char *szBuffer = NULL;
  2565.         hr = GenerateCacheInfo(m_pmcSelectedMesh->pMesh, &szBuffer);
  2566.         if (FAILED(hr))
  2567.             goto e_Exit;
  2568.  
  2569.         pvDialogData = (PVOID)szBuffer;
  2570.  
  2571.         DialogBox(m_hInstance, (LPCTSTR) IDD_INFO, m_hwnd, (DLGPROC) DlgProcOutput);
  2572.  
  2573.         delete []szBuffer;
  2574.     }
  2575.  
  2576. e_Exit:
  2577.     delete []rgdwFaceRemap;
  2578.     GXRELEASE(pbufVertRemap);
  2579.  
  2580.     return;
  2581. }
  2582.  
  2583. HRESULT 
  2584. TrivialData::DisplayCacheBehavior()
  2585. {
  2586.     HRESULT hr = S_OK;
  2587.     char *szBuffer = NULL;
  2588.  
  2589.     if ((m_pmcSelectedMesh != NULL) && (m_pmcSelectedMesh->pMesh != NULL))
  2590.     {
  2591.         hr = GenerateCacheInfo(m_pmcSelectedMesh->pMesh, &szBuffer);
  2592.         if (FAILED(hr))
  2593.             return hr;
  2594.  
  2595.         pvDialogData = (PVOID)szBuffer;
  2596.  
  2597.         DialogBox(m_hInstance, (LPCTSTR) IDD_INFO, m_hwnd, (DLGPROC) DlgProcOutput);
  2598.  
  2599.         delete []szBuffer;
  2600.     }
  2601.  
  2602.     return hr;
  2603. }
  2604.  
  2605. void 
  2606. TrivialData::SetSoftMinLOD()
  2607. {
  2608.     // skip if not a PMesh
  2609.     if ((m_pmcSelectedMesh == NULL) || !(m_pmcSelectedMesh->bPMMeshMode))
  2610.     {
  2611.         return;
  2612.     }
  2613.  
  2614.     m_pmcSelectedMesh->m_cMinVerticesSoft = m_pmcSelectedMesh->pPMMesh->GetNumVertices();
  2615. }
  2616.  
  2617. void 
  2618. TrivialData::SetSoftMaxLOD()
  2619. {
  2620.     // skip if not a PMesh
  2621.     if ((m_pmcSelectedMesh == NULL) || !(m_pmcSelectedMesh->bPMMeshMode))
  2622.     {
  2623.         return;
  2624.     }
  2625.  
  2626.     m_pmcSelectedMesh->m_cMaxVerticesSoft = m_pmcSelectedMesh->pPMMesh->GetNumVertices();
  2627. }
  2628.  
  2629. void 
  2630. TrivialData::ResetSoftMinLOD()
  2631. {
  2632.     // skip if not a PMesh
  2633.     if ((m_pmcSelectedMesh == NULL) || !(m_pmcSelectedMesh->bPMMeshMode))
  2634.     {
  2635.         return;
  2636.     }
  2637.  
  2638.     m_pmcSelectedMesh->m_cMinVerticesSoft = m_pmcSelectedMesh->pPMMesh->GetMinVertices();
  2639. }
  2640.  
  2641. void 
  2642. TrivialData::ResetSoftMaxLOD()
  2643. {
  2644.     // skip if not a PMesh
  2645.     if ((m_pmcSelectedMesh == NULL) || !(m_pmcSelectedMesh->bPMMeshMode))
  2646.     {
  2647.         return;
  2648.     }
  2649.  
  2650.     m_pmcSelectedMesh->m_cMaxVerticesSoft = m_pmcSelectedMesh->pPMMesh->GetMaxVertices();
  2651. }
  2652.  
  2653. void 
  2654. TrivialData::TrimPMeshToSoftLimits()
  2655. {
  2656.     // skip if not a PMesh
  2657.     if ((m_pmcSelectedMesh == NULL) || !(m_pmcSelectedMesh->bPMMeshMode))
  2658.     {
  2659.         return;
  2660.     }
  2661.  
  2662.     m_pmcSelectedMesh->pPMMesh->TrimByVertices(m_pmcSelectedMesh->m_cMinVerticesSoft, m_pmcSelectedMesh->m_cMaxVerticesSoft, NULL, NULL);
  2663.  
  2664.     AdjustScrollbar();
  2665. }
  2666.  
  2667. void
  2668. TrivialData::SnapshotSelected()
  2669. {
  2670.     LPD3DXMESH pMeshTemp;
  2671.     HRESULT hr;
  2672.  
  2673.     if (m_pmcSelectedMesh != NULL)
  2674.     {
  2675.         if (m_pmcSelectedMesh->bSimplifyMode)
  2676.         {
  2677.             LPD3DXPMESH pPMesh = m_pmcSelectedMesh->pPMMesh;
  2678.  
  2679.             hr = m_pmcSelectedMesh->pSimpMesh->CloneMesh(m_pmcSelectedMesh->pSimpMesh->GetOptions(), NULL, m_pDevice, m_pmcSelectedMesh->rgdwAdjacency, NULL, &pMeshTemp);
  2680.             GXASSERT(!FAILED(hr));
  2681.  
  2682.             GXRELEASE(m_pmcSelectedMesh->pSimpMesh);
  2683.             GXRELEASE(m_pmcSelectedMesh->ptmDrawMesh);
  2684.  
  2685.             m_pmcSelectedMesh->ptmDrawMesh = pMeshTemp;
  2686.             m_pmcSelectedMesh->pMesh = pMeshTemp;
  2687.             pMeshTemp->AddRef();
  2688.  
  2689.             m_pmcSelectedMesh->bSimplifyMode = FALSE;
  2690.             AdjustScrollbar();
  2691.  
  2692.             hr = m_pmcSelectedMesh->UpdateViews(m_pdeSelected);
  2693.             if (FAILED(hr))
  2694.                 return;
  2695.         }
  2696.         else if (m_pmcSelectedMesh->bPMMeshMode)
  2697.         {
  2698.             LPD3DXPMESH pPMesh = m_pmcSelectedMesh->pPMMesh;
  2699.  
  2700.             hr = m_pmcSelectedMesh->pPMMesh->Optimize(D3DXMESH_MANAGED|D3DXMESHOPT_COMPACT|D3DXMESHOPT_ATTRSORT, m_pmcSelectedMesh->rgdwAdjacency, NULL, NULL, &pMeshTemp);
  2701.             GXASSERT(!FAILED(hr));
  2702.  
  2703.             GXRELEASE(m_pmcSelectedMesh->pPMMesh);
  2704.             GXRELEASE(m_pmcSelectedMesh->ptmDrawMesh);
  2705.  
  2706.             m_pmcSelectedMesh->ptmDrawMesh = pMeshTemp;
  2707.             m_pmcSelectedMesh->pMesh = pMeshTemp;
  2708.             pMeshTemp->AddRef();
  2709.  
  2710.             m_pmcSelectedMesh->bPMMeshMode = FALSE;
  2711.             AdjustScrollbar();
  2712.  
  2713.             hr = m_pmcSelectedMesh->UpdateViews(m_pdeSelected);
  2714.             if (FAILED(hr))
  2715.                 return;
  2716.         }
  2717.         else if (m_pmcSelectedMesh->bNPatchMode)
  2718.         {          
  2719.             // if HW, swap in the software tesselated mesh
  2720.             if (m_bHWNPatches)
  2721.             {
  2722.                 GXRELEASE(m_pmcSelectedMesh->ptmDrawMesh);
  2723.                 GXRELEASE(m_pmcSelectedMesh->pMesh);
  2724.                 m_pmcSelectedMesh->ptmDrawMesh = m_pmcSelectedMesh->pSWTesselatedMesh;
  2725.                 m_pmcSelectedMesh->pMesh = m_pmcSelectedMesh->pSWTesselatedMesh;
  2726.                 m_pmcSelectedMesh->pMesh->AddRef();
  2727.                 m_pmcSelectedMesh->pMesh->AddRef();
  2728.             }
  2729.  
  2730.             GXRELEASE(m_pmcSelectedMesh->pSWTesselatedMesh);
  2731.             GXRELEASE(m_pmcSelectedMesh->pMeshToTesselate);
  2732.             delete []m_pmcSelectedMesh->rgdwAdjacencyTesselate;
  2733.             m_pmcSelectedMesh->rgdwAdjacencyTesselate = NULL;
  2734.  
  2735.             m_pmcSelectedMesh->cTesselateLevel = 0;
  2736.             m_pmcSelectedMesh->bNPatchMode = FALSE;
  2737.  
  2738.             hr = m_pmcSelectedMesh->UpdateViews(m_pdeSelected);
  2739.             if (FAILED(hr))
  2740.                 return;
  2741.  
  2742.             AdjustScrollbar();
  2743.         }
  2744.         else if (m_pmcSelectedMesh->bTesselateMode)
  2745.         {          
  2746.             GXRELEASE(m_pmcSelectedMesh->pPatchMesh);
  2747.  
  2748.             m_pmcSelectedMesh->cTesselateLevel = 0;
  2749.             m_pmcSelectedMesh->bTesselateMode = FALSE;
  2750.  
  2751.             hr = m_pmcSelectedMesh->UpdateViews(m_pdeSelected);
  2752.             if (FAILED(hr))
  2753.                 return;
  2754.  
  2755.             AdjustScrollbar();
  2756.         }
  2757.     }
  2758. }
  2759.  
  2760.  
  2761. //HRESULT CreateMaterialBuffer(LPD3DXMATERIAL rgmat, DWORD cmat, LPD3DXBUFFER *ppbufMaterials);
  2762. static HRESULT
  2763. CreateMaterialBuffer(LPD3DXMATERIAL rgmat, DWORD cmat, LPD3DXBUFFER *ppbufMaterials)
  2764. {
  2765.     HRESULT hr = S_OK;
  2766.     DWORD cbTotalStringSize;
  2767.     DWORD iCurOffset;
  2768.     DWORD imat;
  2769.     LPD3DXBUFFER pbufMaterialsOut = NULL;
  2770.     LPD3DXMATERIAL rgmatOut;
  2771.     DWORD cbName;
  2772.  
  2773.     // first calculate the amount of memory needed for the string buffers
  2774.     cbTotalStringSize = 0;
  2775.     for (imat = 0; imat < cmat; imat++)
  2776.     {
  2777.         if (rgmat[imat].pTextureFilename != NULL)
  2778.         {
  2779.             cbTotalStringSize += strlen(rgmat[imat].pTextureFilename) + 1;
  2780.         }
  2781.     }
  2782.  
  2783.     hr = D3DXCreateBuffer(sizeof(D3DXMATERIAL) * cmat + cbTotalStringSize, &pbufMaterialsOut);
  2784.     if (FAILED(hr))
  2785.         goto e_Exit;
  2786.  
  2787.     rgmatOut = (LPD3DXMATERIAL)pbufMaterialsOut->GetBufferPointer();
  2788.  
  2789.     // fist copy the materials info into the new array (note: string pointers are now incorrect)
  2790.     memcpy(rgmatOut, rgmat, sizeof(D3DXMATERIAL) * cmat);
  2791.  
  2792.     // start allocating strings just after the last material
  2793.     iCurOffset = sizeof(D3DXMATERIAL) * cmat;
  2794.     for (imat = 0; imat < cmat; imat++)
  2795.     {
  2796.         if (rgmat[imat].pTextureFilename != NULL)
  2797.         {
  2798.             rgmatOut[imat].pTextureFilename = ((char*)rgmatOut) + iCurOffset;
  2799.  
  2800.             cbName = strlen(rgmat[imat].pTextureFilename) + 1;
  2801.             memcpy(rgmatOut[imat].pTextureFilename, rgmat[imat].pTextureFilename, cbName);
  2802.  
  2803.             iCurOffset += cbName;
  2804.         }
  2805.     }
  2806.  
  2807.     GXASSERT(iCurOffset == sizeof(D3DXMATERIAL) * cmat + cbTotalStringSize);
  2808.  
  2809.     *ppbufMaterials = pbufMaterialsOut;
  2810.     pbufMaterialsOut = NULL;
  2811.  
  2812. e_Exit:
  2813.     GXRELEASE(pbufMaterialsOut);
  2814.     return hr;
  2815. }
  2816.  
  2817.  
  2818. static HRESULT
  2819. MergeMaterialBuffers
  2820.     (
  2821.     D3DXMATERIAL *pMat1, 
  2822.     DWORD cmat1, 
  2823.     D3DXMATERIAL *pMat2, 
  2824.     DWORD cmat2, 
  2825.     LPD3DXBUFFER *ppbufMaterials
  2826.     )
  2827. {
  2828.     HRESULT hr = S_OK;
  2829.     D3DXMATERIAL *rgmatTemp = NULL;
  2830.     D3DXMATERIAL *rgmat1;
  2831.     D3DXMATERIAL *rgmat2;
  2832.  
  2833.     if (pMat1 == NULL)
  2834.     {
  2835.         if (pMat2 == NULL)
  2836.         {
  2837.             *ppbufMaterials = NULL;
  2838.         }
  2839.         else
  2840.         {
  2841.             hr = CreateMaterialBuffer(pMat2, cmat2, ppbufMaterials);
  2842.             if (FAILED(hr))
  2843.                 goto e_Exit;
  2844.         }
  2845.     }
  2846.     else if (pMat2 == NULL)
  2847.     {
  2848.         hr = CreateMaterialBuffer(pMat1, cmat1, ppbufMaterials);
  2849.         if (FAILED(hr))
  2850.             goto e_Exit;
  2851.     }
  2852.     else  // both have materials
  2853.     {
  2854.         // make an array contains the color info and pointers to the original strings
  2855.         //   that is the two arrays combined
  2856.         rgmatTemp = new D3DXMATERIAL[cmat1 + cmat2];
  2857.         if (rgmatTemp == NULL)
  2858.         {
  2859.             hr = E_OUTOFMEMORY;
  2860.             goto e_Exit;
  2861.         }
  2862.  
  2863.         memcpy(rgmatTemp, pMat1, sizeof(D3DXMATERIAL) * cmat1);
  2864.         memcpy(rgmatTemp + cmat1, pMat2, sizeof(D3DXMATERIAL) * cmat2);
  2865.  
  2866.         // then use the CreateMaterialBuffer call to take and make a buffer out of the "merged" array
  2867.         hr = CreateMaterialBuffer(rgmatTemp, cmat1 + cmat2, ppbufMaterials);
  2868.         if (FAILED(hr))
  2869.             goto e_Exit;
  2870.     }
  2871.  
  2872. e_Exit:
  2873.     delete []rgmatTemp;
  2874.     return hr;
  2875.  
  2876. }
  2877.  
  2878. static DWORD DwCombineFVFs(DWORD dwFVF1, DWORD dwFVF2)
  2879. {
  2880.     DXCrackFVF cfvf1(dwFVF1);
  2881.     DXCrackFVF cfvf2(dwFVF2);
  2882.     DWORD dwWeights;
  2883.     DWORD dwTex;
  2884.     DWORD dwOut;
  2885.  
  2886.     dwWeights = max(cfvf1.CWeights(), cfvf2.CWeights());
  2887.     if (dwWeights > 0)
  2888.     {
  2889.         dwWeights *= 2;
  2890.         dwWeights += 4;
  2891.         dwOut = dwWeights;
  2892.     }
  2893.     else
  2894.     {
  2895.         dwOut = D3DFVF_XYZ;
  2896.     }
  2897.  
  2898.     if (cfvf1.BNormal() || cfvf2.BNormal())
  2899.         dwOut |= D3DFVF_NORMAL;
  2900.  
  2901.     if (cfvf1.BDiffuse() || cfvf2.BDiffuse())
  2902.         dwOut |= D3DFVF_DIFFUSE;
  2903.  
  2904.     if (cfvf1.BSpecular() || cfvf2.BSpecular())
  2905.         dwOut |= D3DFVF_SPECULAR;
  2906.  
  2907.     dwTex = max(cfvf1.CTexCoords(), cfvf2.CTexCoords());
  2908.     if (dwTex > 0)
  2909.     {
  2910.         dwOut |= (dwTex << D3DFVF_TEXCOUNT_SHIFT);
  2911.     }
  2912.  
  2913.     return dwOut;
  2914. }
  2915.  
  2916. HRESULT D3DXMergeMeshes
  2917.     (
  2918.     LPD3DXMESH pMesh1,
  2919.     PDWORD rgdwAdjacency1,
  2920.     D3DXMATERIAL *pMaterials1,
  2921.     DWORD cmat1,
  2922.     LPD3DXMESH pMesh2,
  2923.     PDWORD rgdwAdjacency2,
  2924.     D3DXMATERIAL *pMaterials2,
  2925.     DWORD cmat2,
  2926.     LPDIRECT3DDEVICE9 pD3DDevice,
  2927.     LPD3DXMESH *ppMeshOut,
  2928.     LPD3DXBUFFER *ppbufAdjacencyOut,
  2929.     LPD3DXBUFFER *ppbufMaterialsOut,
  2930.     LPDWORD pcmatOut
  2931.     )
  2932. {
  2933.     HRESULT hr = S_OK;
  2934.     DWORD cVertices1;
  2935.     DWORD cVertices2;
  2936.     DWORD cVerticesOut;
  2937.     DWORD cFaces1;
  2938.     DWORD cFaces2;
  2939.     DWORD cFacesOut;
  2940.     LPD3DXMESH ptmMeshOut = NULL;
  2941.     LPD3DXBUFFER pbufAdjacencyOut = NULL;
  2942.     PDWORD rgdwAdjacencyOut;
  2943.     PDWORD rgdwAttribs1 = NULL;
  2944.     PDWORD rgdwAttribs2 = NULL;
  2945.     BOOL b16BitIndex;
  2946.     PBYTE pFacesOut = NULL;
  2947.     PDWORD rgdwAttribsOut = NULL;
  2948.     UINT iIndex;
  2949.     UINT iIndex2;
  2950.     DXCrackFVF cfvf(D3DFVF_XYZ);
  2951.     PBYTE pFaces1 = NULL;
  2952.     PBYTE pFaces2 = NULL;
  2953.     PBYTE pvPointsOut = NULL;
  2954.     PBYTE pvPoints1 = NULL;
  2955.     PBYTE    pvPoints2 = NULL;
  2956.     UINT cBytesPerIndex;
  2957.     LPD3DXBUFFER pbufMaterialsOut = NULL;
  2958.     DWORD dwFVF;
  2959.     DWORD dwOptions;
  2960.     LPD3DXMESH pTempMesh1 = NULL;
  2961.     LPD3DXMESH pTempMesh2 = NULL;
  2962.  
  2963.     // need all mesh pointers
  2964.     if ((pMesh1 == NULL) || (pMesh2 == NULL) || (ppMeshOut == NULL))
  2965.     {
  2966.         DPF(0, "Internal error - D3DXMergeMesh: Invalid pMesh1, pMesh2 or ppMeshOut pointers");
  2967.         return D3DXERR_INVALIDDATA;
  2968.     }
  2969.  
  2970.     // number of vertices
  2971.     cVertices1 = pMesh1->GetNumVertices();
  2972.     cVertices2 = pMesh2->GetNumVertices();
  2973.     cVerticesOut = cVertices1 + cVertices2;
  2974.  
  2975.     // number of faces
  2976.     cFaces1 = pMesh1->GetNumFaces();
  2977.     cFaces2 = pMesh2->GetNumFaces();
  2978.     cFacesOut = cFaces1 + cFaces2;
  2979.  
  2980.     dwOptions = pMesh1->GetOptions();
  2981.  
  2982.     if ((cFacesOut >= UNUSED16) 
  2983.         || (cVerticesOut >= UNUSED16)
  2984.         || (pMesh2->GetOptions() & D3DXMESH_32BIT))
  2985.     {
  2986.         dwOptions |= D3DXMESH_32BIT;
  2987.     }
  2988.     b16BitIndex = !(dwOptions & D3DXMESH_32BIT);
  2989.  
  2990.     if (pMesh1->GetFVF() != pMesh2->GetFVF())
  2991.     {
  2992.         dwFVF = DwCombineFVFs(pMesh1->GetFVF(), pMesh2->GetFVF());
  2993.     }
  2994.     else
  2995.     {
  2996.         dwFVF = pMesh1->GetFVF();
  2997.     }
  2998.  
  2999.     if ((pMesh1->GetOptions() != dwOptions) 
  3000.         || (pMesh1->GetFVF() != dwFVF))
  3001.     {
  3002.         hr = pMesh1->CloneMeshFVF(dwOptions, dwFVF, pD3DDevice, &pTempMesh1);
  3003.         if (FAILED(hr))
  3004.             return hr;
  3005.  
  3006.         // NOTE: don't release pMesh1, owned by caller, just release pTempMesh1 on exit
  3007.         pMesh1 = pTempMesh1;
  3008.     }
  3009.  
  3010.     if ((pMesh2->GetOptions() != dwOptions) 
  3011.         || (pMesh2->GetFVF() != dwFVF))
  3012.     {
  3013.         hr = pMesh2->CloneMeshFVF(dwOptions, dwFVF, pD3DDevice, &pTempMesh2);
  3014.         if (FAILED(hr))
  3015.             return hr;
  3016.         
  3017.         // NOTE: don't release pMesh2, owned by caller, just release pTempMesh2 on exit
  3018.         pMesh2 = pTempMesh2;
  3019.     }
  3020.  
  3021.  
  3022.     // had better have the same options
  3023.     GXASSERT((pMesh1->GetOptions() == pMesh2->GetOptions()) && (pMesh1->GetFVF() == pMesh2->GetFVF()));
  3024.     GXASSERT((pMesh1->GetOptions() == dwOptions) && (pMesh1->GetFVF() == dwFVF));
  3025.     GXASSERT(!b16BitIndex || ((cFacesOut < UNUSED16) && (cVerticesOut < UNUSED16)));
  3026.     GXASSERT((rgdwAdjacency1 != NULL) && (rgdwAdjacency2 != NULL) && (ppbufAdjacencyOut != NULL));
  3027.  
  3028.  
  3029.     hr = pMesh1->LockAttributeBuffer(D3DLOCK_READONLY, &rgdwAttribs1);
  3030.     if (FAILED(hr))
  3031.         goto e_Exit;
  3032.  
  3033.     hr = pMesh2->LockAttributeBuffer(D3DLOCK_READONLY, &rgdwAttribs2);
  3034.     if (FAILED(hr))
  3035.         goto e_Exit;
  3036.  
  3037.     hr = pMesh1->LockIndexBuffer(D3DLOCK_READONLY, (LPVOID*)&pFaces1);
  3038.     if (FAILED(hr))
  3039.         goto e_Exit;
  3040.  
  3041.     hr = pMesh2->LockIndexBuffer(D3DLOCK_READONLY, (LPVOID*)&pFaces2);
  3042.     if (FAILED(hr))
  3043.         goto e_Exit;
  3044.  
  3045.     if (b16BitIndex)
  3046.         cBytesPerIndex = sizeof(UINT16);
  3047.     else
  3048.         cBytesPerIndex = sizeof(UINT32);
  3049.  
  3050.     // generate a material buffer that is two material sets concated together
  3051.     hr = MergeMaterialBuffers(pMaterials1, cmat1, pMaterials2, cmat2, &pbufMaterialsOut);
  3052.     if (FAILED(hr))
  3053.         goto e_Exit;
  3054.  
  3055.     //create the mesh to fill
  3056.     hr = D3DXCreateMeshFVF(cFacesOut, cVerticesOut,
  3057.                                 dwOptions, dwFVF,
  3058.                                 pD3DDevice, &ptmMeshOut);
  3059.     if (FAILED(hr))
  3060.         goto e_Exit;
  3061.  
  3062.     hr = ptmMeshOut->LockIndexBuffer(0, (LPVOID*)&pFacesOut);
  3063.     if (FAILED(hr))
  3064.         goto e_Exit;
  3065.  
  3066.     hr = ptmMeshOut->LockAttributeBuffer(0, &rgdwAttribsOut);
  3067.     if (FAILED(hr))
  3068.         goto e_Exit;
  3069.  
  3070.     hr = D3DXCreateBuffer(cFacesOut * sizeof(DWORD) * 3, &pbufAdjacencyOut);
  3071.     if (FAILED(hr))
  3072.         goto e_Exit;
  3073.     rgdwAdjacencyOut = (PDWORD)pbufAdjacencyOut->GetBufferPointer();
  3074.  
  3075.     // now copy and remap the face data
  3076.  
  3077.     memcpy(pFacesOut, pFaces1, cBytesPerIndex * cFaces1 * 3);
  3078.     memcpy(rgdwAttribsOut, rgdwAttribs1, sizeof(DWORD) * cFaces1);
  3079.     for (iIndex = 0; iIndex < cFaces1*3; iIndex++)
  3080.     {
  3081.         if (rgdwAdjacency1 != NULL)
  3082.         {
  3083.             rgdwAdjacencyOut[iIndex] = rgdwAdjacency1[iIndex];
  3084.         }
  3085.         else
  3086.         {
  3087.             rgdwAdjacencyOut[iIndex] = UNUSED32;
  3088.         }
  3089.     }
  3090.  
  3091.     memcpy(pFacesOut + cBytesPerIndex * cFaces1 * 3, pFaces2, cBytesPerIndex * cFaces2 * 3);
  3092.     memcpy(rgdwAttribsOut + cFaces1, rgdwAttribs2, sizeof(DWORD) * cFaces2);
  3093.     for (iIndex = cFaces1 * 3, iIndex2 = 0; iIndex < cFacesOut*3; iIndex++, iIndex2++)
  3094.     {
  3095.         if (rgdwAdjacency2 != NULL)
  3096.         {
  3097.             if (rgdwAdjacency2[iIndex2] == UNUSED32)
  3098.                 rgdwAdjacencyOut[iIndex] = UNUSED32;
  3099.             else
  3100.                 rgdwAdjacencyOut[iIndex] = rgdwAdjacency2[iIndex2] + cFaces1;
  3101.         }
  3102.         else
  3103.         {
  3104.             rgdwAdjacencyOut[iIndex] = UNUSED32;
  3105.         }
  3106.     }
  3107.  
  3108.  
  3109.     if (b16BitIndex)
  3110.     {
  3111.         UINT16 *pFacesTemp;
  3112.         pFacesTemp = (UINT16*)pFacesOut;
  3113.  
  3114.         for (iIndex = cFaces1 * 3; iIndex < cFacesOut * 3; iIndex++)
  3115.         {
  3116.             if (pFacesTemp[iIndex] != UNUSED16)
  3117.                 pFacesTemp[iIndex] += (UINT16)cVertices1;
  3118.         }
  3119.     }
  3120.     else
  3121.     {
  3122.         UINT32 *pFacesTemp;
  3123.         pFacesTemp = (UINT32*)pFacesOut;
  3124.  
  3125.         for (iIndex = cFaces1 * 3; iIndex < cFacesOut * 3; iIndex++)
  3126.         {
  3127.             if (pFacesTemp[iIndex] != UNUSED32)
  3128.                 pFacesTemp[iIndex] += cVertices1;
  3129.         }
  3130.     }
  3131.  
  3132.     for (iIndex = cFaces1; iIndex < cFacesOut; iIndex++)
  3133.     {
  3134.         rgdwAttribsOut[iIndex] += cmat1;
  3135.     }
  3136.  
  3137.     // now copy the vertex data from the two buffers into the one
  3138.  
  3139.     hr = ptmMeshOut->LockVertexBuffer(0, (LPVOID*)&pvPointsOut);
  3140.     if (FAILED(hr))
  3141.         goto e_Exit;
  3142.  
  3143.     hr = pMesh1->LockVertexBuffer(D3DLOCK_READONLY, (LPVOID*)&pvPoints1);
  3144.     if (FAILED(hr))
  3145.         goto e_Exit;
  3146.  
  3147.     hr = pMesh2->LockVertexBuffer(D3DLOCK_READONLY, (LPVOID*)&pvPoints2);
  3148.     if (FAILED(hr))
  3149.         goto e_Exit;
  3150.  
  3151.  
  3152.     cfvf = DXCrackFVF(dwFVF);
  3153.  
  3154.     // finish by copying the two sets of vertex data into the destination buffer
  3155.     memcpy(pvPointsOut, pvPoints1, cfvf.m_cBytesPerVertex * cVertices1);
  3156.     memcpy((PBYTE)pvPointsOut + cfvf.m_cBytesPerVertex * cVertices1, pvPoints2,
  3157.                             cfvf.m_cBytesPerVertex * cVertices2);
  3158.  
  3159.     // all finished, setup return values
  3160.     *ppMeshOut = ptmMeshOut;
  3161.     ptmMeshOut->AddRef();
  3162.     if (ppbufAdjacencyOut != NULL)
  3163.     {
  3164.         *ppbufAdjacencyOut = pbufAdjacencyOut;
  3165.         pbufAdjacencyOut = NULL;
  3166.     }
  3167.     if (ppbufMaterialsOut != NULL)
  3168.     {
  3169.         *ppbufMaterialsOut = pbufMaterialsOut;
  3170.         pbufMaterialsOut = NULL;
  3171.     }
  3172.     if (pcmatOut != NULL)
  3173.         *pcmatOut = cmat1 + cmat2;
  3174.  
  3175. //    GXASSERT(CheckAdjacency(rgdwAdjacencyOut, cFacesOut));
  3176.  
  3177. e_Exit:
  3178.     if (pFacesOut != NULL)
  3179.     {
  3180.         ptmMeshOut->UnlockIndexBuffer();
  3181.     }
  3182.     if (rgdwAttribsOut != NULL)
  3183.     {
  3184.         ptmMeshOut->UnlockAttributeBuffer();
  3185.     }
  3186.     if (rgdwAttribs1 != NULL)
  3187.     {
  3188.         pMesh1->UnlockAttributeBuffer();
  3189.     }
  3190.     if (rgdwAttribs2 != NULL)
  3191.     {
  3192.         pMesh2->UnlockAttributeBuffer();
  3193.     }
  3194.  
  3195.     if (pFaces1 != NULL)
  3196.     {
  3197.         pMesh1->UnlockIndexBuffer();
  3198.     }
  3199.     if (pFaces2 != NULL)
  3200.     {
  3201.         pMesh2->UnlockIndexBuffer();
  3202.     }
  3203.  
  3204.     if (pvPointsOut != NULL)
  3205.     {
  3206.         ptmMeshOut->UnlockVertexBuffer();
  3207.     }
  3208.     if (pvPoints1 != NULL)
  3209.     {
  3210.         pMesh1->UnlockVertexBuffer();
  3211.     }
  3212.     if (pvPoints2 != NULL)
  3213.     {
  3214.         pMesh2->UnlockVertexBuffer();
  3215.     }
  3216.  
  3217.     GXRELEASE(ptmMeshOut);
  3218.     GXRELEASE(pbufAdjacencyOut);
  3219.     GXRELEASE(pbufMaterialsOut);
  3220.  
  3221.     GXRELEASE(pTempMesh1);
  3222.     GXRELEASE(pTempMesh2);
  3223.  
  3224.     return hr;
  3225. }
  3226.  
  3227.  
  3228. HRESULT
  3229. MergeMeshes
  3230.     (
  3231.     SFrame *pframe, 
  3232.     LPDIRECT3DDEVICE9 pDevice,    
  3233.     LPD3DXMESH *ppMeshMerged, 
  3234.     LPD3DXBUFFER *ppbufAdjacencyMerged,
  3235.     LPD3DXBUFFER *ppbufMaterialsMerged,
  3236.     DWORD *pcMaterialsMerged
  3237.     )
  3238. {
  3239.     HRESULT hr = S_OK;
  3240.     SMeshContainer *pmcCur = pframe->pmcMesh;
  3241.     SFrame *pframeCur;
  3242.     DWORD cFaces;
  3243.     LPD3DXMESH pMeshOut;
  3244.     LPD3DXBUFFER pbufAdjacencyOut;
  3245.     LPD3DXBUFFER pbufMaterialsOut;
  3246.     DWORD cMatOut;
  3247.     DWORD cVertices;
  3248.     DWORD iVert;
  3249.     DXCrackFVF cfvf(D3DFVF_XYZ);
  3250.     PBYTE pvPoints;
  3251.     PBYTE pvPoint;
  3252.     D3DXVECTOR3 *pvVertexCur;
  3253.     LPD3DXMESH pMeshTemp = NULL;
  3254.     LPDIRECT3DDEVICE9 pD3DDevice;
  3255.  
  3256.     while (pmcCur != NULL)
  3257.     {
  3258.         if (pmcCur->pMesh != NULL)
  3259.         {
  3260.             cfvf = DXCrackFVF(pmcCur->pMesh->GetFVF());
  3261.  
  3262.             hr = pmcCur->pMesh->GetDevice(&pD3DDevice);
  3263.             if (FAILED(hr))
  3264.                 goto e_Exit;
  3265.             pD3DDevice->Release();
  3266.  
  3267.             // make a temp mesh to modify
  3268.             hr = pmcCur->pMesh->CloneMeshFVF(pmcCur->pMesh->GetOptions(), cfvf.m_dwFVF, pD3DDevice, &pMeshTemp);
  3269.             if (FAILED(hr))
  3270.                 goto e_Exit;
  3271.  
  3272.     // first transform into world space
  3273.             hr = pMeshTemp->LockVertexBuffer(0, (LPVOID*)&pvPoints);
  3274.             if (FAILED(hr))
  3275.                 goto e_Exit;
  3276.  
  3277.             cVertices = pMeshTemp->GetNumVertices();
  3278.             for (iVert = 0; iVert < cVertices; iVert++)
  3279.             {
  3280.                 pvPoint = cfvf.GetArrayElem(pvPoints, iVert);
  3281.  
  3282.                 pvVertexCur = cfvf.PvGetPosition(pvPoint);
  3283.  
  3284.                 D3DXVec3TransformCoord(pvVertexCur, pvVertexCur, &pframe->matCombined);
  3285.  
  3286.                 if (cfvf.BNormal())
  3287.                 {
  3288.                     pvVertexCur = cfvf.PvGetNormal(pvPoint);
  3289.  
  3290.                     D3DXVec3TransformNormal(pvVertexCur, pvVertexCur, &pframe->matCombined);
  3291.                     D3DXVec3Normalize(pvVertexCur, pvVertexCur);
  3292.                 }
  3293.             }
  3294.             pMeshTemp->UnlockVertexBuffer();
  3295.  
  3296.     // now merge with the other mesh data - either first - just addref
  3297.             // or if nth, use merge function
  3298.  
  3299.             if (*ppMeshMerged == NULL)
  3300.             {
  3301.                 *ppMeshMerged = pMeshTemp;
  3302.                 pMeshTemp->AddRef();
  3303.  
  3304.                 cFaces = pMeshTemp->GetNumFaces();
  3305.  
  3306.                 hr = D3DXCreateBuffer(cFaces * sizeof(DWORD) * 3, ppbufAdjacencyMerged);
  3307.                 if (FAILED(hr))
  3308.                     goto e_Exit;
  3309.                 memcpy((*ppbufAdjacencyMerged)->GetBufferPointer(), pmcCur->rgdwAdjacency, sizeof(DWORD)*3*cFaces);
  3310.  
  3311.                 hr = CreateMaterialBuffer(pmcCur->rgMaterials, pmcCur->NumMaterials, ppbufMaterialsMerged);
  3312.                 if (FAILED(hr))
  3313.                     goto e_Exit;
  3314.                 *pcMaterialsMerged = pmcCur->NumMaterials;
  3315.             }
  3316.             else
  3317.             {
  3318.                 hr = D3DXMergeMeshes
  3319.                     (
  3320.                     pMeshTemp,
  3321.                     pmcCur->rgdwAdjacency,
  3322.                     pmcCur->rgMaterials,
  3323.                     pmcCur->NumMaterials,
  3324.                     *ppMeshMerged,
  3325.                     (DWORD*)(*ppbufAdjacencyMerged)->GetBufferPointer(),
  3326.                     (D3DXMATERIAL*)(*ppbufMaterialsMerged)->GetBufferPointer(),
  3327.                     *pcMaterialsMerged,
  3328.                     pDevice,
  3329.                     &pMeshOut,
  3330.                     &pbufAdjacencyOut,
  3331.                     &pbufMaterialsOut,
  3332.                     &cMatOut
  3333.                     );
  3334.                 if (FAILED(hr))
  3335.                     goto e_Exit;
  3336.  
  3337.                 GXRELEASE(*ppMeshMerged);
  3338.                 GXRELEASE(*ppbufAdjacencyMerged);
  3339.                 GXRELEASE(*ppbufMaterialsMerged);
  3340.  
  3341.                 *ppMeshMerged = pMeshOut;
  3342.                 *ppbufAdjacencyMerged = pbufAdjacencyOut;
  3343.                 *ppbufMaterialsMerged = pbufMaterialsOut;
  3344.                 *pcMaterialsMerged = cMatOut;
  3345.             }
  3346.  
  3347.             GXRELEASE(pMeshTemp);
  3348.         }
  3349.  
  3350.  
  3351.         pmcCur = (SMeshContainer*)pmcCur->pNextMeshContainer;
  3352.     }
  3353.  
  3354.     pframeCur = pframe->pframeFirstChild;
  3355.     while (pframeCur != NULL)
  3356.     {
  3357.         hr = MergeMeshes(pframeCur, pDevice, ppMeshMerged, ppbufAdjacencyMerged, ppbufMaterialsMerged, pcMaterialsMerged);
  3358.         if (FAILED(hr))
  3359.             goto e_Exit;
  3360.  
  3361.         pframeCur = pframeCur->pframeSibling;
  3362.     }
  3363.  
  3364. e_Exit:
  3365.     GXRELEASE(pMeshTemp);
  3366.     return hr;
  3367. }
  3368.  
  3369. void
  3370. TrivialData::MergeMeshes()
  3371. {
  3372.     HRESULT hr = S_OK;;
  3373.     LPD3DXMESH pMeshMerged = NULL;
  3374.     LPD3DXBUFFER pbufAdjacencyMerged = NULL;
  3375.     LPD3DXBUFFER pbufMaterialsMerged = NULL;
  3376.     DWORD cMaterialsMerged;
  3377.  
  3378.     if (m_pdeSelected != NULL)
  3379.     {
  3380.         hr = ::MergeMeshes(m_pdeSelected->pframeRoot, m_pDevice,    
  3381.                                 &pMeshMerged, &pbufAdjacencyMerged,
  3382.                                 &pbufMaterialsMerged, &cMaterialsMerged);
  3383.         if (FAILED(hr))
  3384.             goto e_Exit;
  3385.         if (pMeshMerged == NULL)
  3386.         {
  3387.             MessageBox(m_hwnd, "No mesh data found to collapse, data might be present as PMeshes that cannot be collapsed.  Snapshot must be called first.", "CollapseMeshes Failed", MB_OK);
  3388.             goto e_Exit;
  3389.         }
  3390.  
  3391.         hr = AddMeshToDrawList("", pMeshMerged, NULL, pbufAdjacencyMerged, pbufMaterialsMerged, NULL, cMaterialsMerged);
  3392.         if (FAILED(hr))
  3393.             goto e_Exit;
  3394.  
  3395.         m_dwFaceSelected = UNUSED32;
  3396.         m_dwVertexSelected = UNUSED32;
  3397.         UpdateSelectionInfo();
  3398.     }
  3399.  
  3400. e_Exit:
  3401.     GXRELEASE(pMeshMerged);
  3402.     GXRELEASE(pbufAdjacencyMerged);
  3403.     GXRELEASE(pbufMaterialsMerged);
  3404.  
  3405.     return;
  3406. }
  3407. HRESULT
  3408. SMeshContainer::UpdateSkinInfo()
  3409. {
  3410.     HRESULT hr = S_OK;
  3411.     LPD3DXSKININFO pSkinInfoTemp = NULL;
  3412.     LPDIRECT3DDEVICE9 pD3DDevice = NULL;
  3413.     DWORD dwFVFNoWeights;
  3414.     UINT iBone, cBones;
  3415.     LPD3DXBONECOMBINATION pBoneComb;
  3416.     DWORD *rgdwAttribs;
  3417.     UINT iAttrib;
  3418.     UINT iFaceStart;
  3419.     UINT iFaceEnd;
  3420.     UINT iFace;
  3421.     D3DVERTEXELEMENT9 pDecl[MAX_FVF_DECL_SIZE];
  3422.  
  3423.     // the SkinInfo matches the mesh if doing software skinning
  3424.     if (m_Method == SOFTWARE)
  3425.         goto e_Exit;
  3426.  
  3427.     hr = pMesh->GetDevice(&pD3DDevice);
  3428.     if (FAILED(hr))
  3429.         goto e_Exit;
  3430.  
  3431.     GXRELEASE(m_pOrigMesh);
  3432.  
  3433.     pMesh->GetDeclaration(pDecl);
  3434.  
  3435.     // drop all the weights from the decl
  3436.     RemoveDeclElement(D3DDECLUSAGE_BLENDWEIGHT, 0, pDecl);
  3437.     RemoveDeclElement(D3DDECLUSAGE_BLENDINDICES, 0, pDecl);
  3438.  
  3439.     hr = pMesh->CloneMesh(D3DXMESH_SYSTEMMEM, pDecl, pD3DDevice, &m_pOrigMesh);
  3440.     if (FAILED(hr))
  3441.         goto e_Exit;
  3442.  
  3443.     m_pOrigMesh->LockAttributeBuffer(0, &rgdwAttribs);
  3444.  
  3445.     pBoneComb = reinterpret_cast<LPD3DXBONECOMBINATION>(m_pBoneCombinationBuf->GetBufferPointer());
  3446.     for (iAttrib = 0; iAttrib < m_cAttributeGroups; iAttrib++)
  3447.     {
  3448.         iFaceStart = pBoneComb[iAttrib].FaceStart;
  3449.         iFaceEnd = iFaceStart + pBoneComb[iAttrib].FaceCount;
  3450.         for (iFace = iFaceStart; iFace < iFaceEnd; iFace++)
  3451.         {
  3452.             rgdwAttribs[iFace] = pBoneComb[iAttrib].AttribId;
  3453.         }
  3454.     }
  3455.  
  3456.     m_pOrigMesh->UnlockAttributeBuffer();
  3457.  
  3458.     hr = D3DXCreateSkinInfoFromBlendedMesh(
  3459.                             pMesh, 
  3460.                             pSkinInfo->GetNumBones(), 
  3461.                             (LPD3DXBONECOMBINATION)(m_pBoneCombinationBuf->GetBufferPointer()), 
  3462.                             &pSkinInfoTemp);
  3463.     if (FAILED(hr))
  3464.         goto e_Exit;
  3465.  
  3466.     // copy the bone names and offset matrices from one skin info to the other
  3467.     cBones = pSkinInfo->GetNumBones();
  3468.     for (iBone = 0; iBone < cBones; iBone++)
  3469.     {
  3470.         pSkinInfoTemp->SetBoneName(iBone, pSkinInfo->GetBoneName(iBone));
  3471.         pSkinInfoTemp->SetBoneOffsetMatrix(iBone, pSkinInfo->GetBoneOffsetMatrix(iBone));
  3472.     }
  3473.  
  3474.     // swap from the old to the new skin info
  3475.     pSkinInfo->Release();
  3476.     pSkinInfo = pSkinInfoTemp;
  3477.     pSkinInfoTemp = NULL;
  3478.  
  3479. e_Exit:
  3480.     GXRELEASE(pSkinInfoTemp);
  3481.     GXRELEASE(pD3DDevice);
  3482.     return hr;
  3483. }
  3484.  
  3485. HRESULT
  3486. SMeshContainer::UpdateViews
  3487.     (
  3488.     SDrawElement *pde
  3489.     )
  3490. {
  3491.     HRESULT hr;
  3492.     DWORD iTexCoord;
  3493.     DWORD ipattr;
  3494.     LPD3DXBONECOMBINATION rgBoneComb;
  3495.     LPD3DXSKININFO pSkinInfoTemp;
  3496.     LPDIRECT3DDEVICE9 pD3DDevice;
  3497.  
  3498.  
  3499.     // first update the skin mesh if present
  3500.     if ((pSkinInfo != NULL) && (m_Method != SOFTWARE) && (pMesh != NULL))
  3501.     {
  3502.         ptmDrawMesh->GetAttributeTable(m_rgaeAttributeTable, NULL);
  3503.  
  3504.         // some ops want to know if there is a skinned mesh somewhere
  3505.         pde->bSkinnedMeshInHeirarchy = TRUE;
  3506.  
  3507.         // now update the bone combination table
  3508.         rgBoneComb = (LPD3DXBONECOMBINATION)(m_pBoneCombinationBuf->GetBufferPointer());
  3509.         for (ipattr = 0; ipattr < m_cAttributeGroups; ipattr++)
  3510.         {
  3511.             rgBoneComb[ipattr].FaceStart = m_rgaeAttributeTable[ipattr].FaceStart;
  3512.             rgBoneComb[ipattr].FaceCount = m_rgaeAttributeTable[ipattr].FaceCount;
  3513.             rgBoneComb[ipattr].VertexStart = m_rgaeAttributeTable[ipattr].VertexStart;
  3514.             rgBoneComb[ipattr].VertexCount= m_rgaeAttributeTable[ipattr].VertexCount;
  3515.         }
  3516.  
  3517.         hr = UpdateSkinInfo();
  3518.         if (FAILED(hr))
  3519.             return hr;
  3520.  
  3521.         GXRELEASE(m_pSkinnedMesh);
  3522.  
  3523.  
  3524.         hr = m_pOrigMesh->GetDevice(&pD3DDevice);
  3525.         if (FAILED(hr))
  3526.             return hr;
  3527.  
  3528.         // for picking purposes, we always need a sysmem mesh to use software skinning with
  3529.         //   same as orig mesh.  orig mesh is skinned into this mesh for picking
  3530.         hr = m_pOrigMesh->CloneMesh(D3DXMESH_SYSTEMMEM, NULL,
  3531.                                               pD3DDevice, &m_pSkinnedMesh);
  3532.         pD3DDevice->Release();
  3533.         if (FAILED(hr))
  3534.             return hr;
  3535.     }
  3536.  
  3537.     hr = m_aoAdjacency.Init(ptmDrawMesh, rgdwAdjacency);
  3538.     if (FAILED(hr))
  3539.         return hr;
  3540.  
  3541.     hr = m_eoEdges.Init(ptmDrawMesh, rgdwAdjacency);
  3542.     if (FAILED(hr))
  3543.         return hr;
  3544.  
  3545.     hr = m_snNormals.Init(ptmDrawMesh, UNUSED32, pde->fRadius / 20.0f);
  3546.     if (FAILED(hr))
  3547.         return hr;
  3548.  
  3549.     hr = m_soStrips.Init(ptmDrawMesh);
  3550.     if (FAILED(hr))
  3551.         return hr;
  3552.  
  3553.     for (iTexCoord = 0; iTexCoord < x_cpsnTexCoords; iTexCoord++)
  3554.     {
  3555.         // if already created (viewed at some point), or now viewed, but not created
  3556.         if ((m_rgpsnTexCoords[iTexCoord] != NULL) || (pde->dwTexCoordsCalculated & (1<<iTexCoord)))
  3557.         {
  3558.             // allocate a view if one is not present already
  3559.             if (m_rgpsnTexCoords[iTexCoord] == NULL)
  3560.             {
  3561.                 m_rgpsnTexCoords[iTexCoord] = new CShowNormals();
  3562.                 if (m_rgpsnTexCoords[iTexCoord] == NULL)
  3563.                     return E_OUTOFMEMORY;
  3564.             }
  3565.  
  3566.  
  3567.             hr = m_rgpsnTexCoords[iTexCoord]->Init(ptmDrawMesh, iTexCoord, pde->fRadius / 20.0f);
  3568.             if (FAILED(hr))
  3569.                 return hr;            
  3570.         }
  3571.     }
  3572.  
  3573.     // if npatching, initialize npatch edge mode view
  3574.     if (bNPatchMode)
  3575.     {
  3576.         hr = m_npoNPatchOutline.Init(pSWTesselatedMesh, cTesselateLevel+1);
  3577.         if (FAILED(hr))
  3578.             return hr;
  3579.     }
  3580.     else
  3581.     {
  3582.         hr = m_npoNPatchOutline.CreateEmptyOutline();
  3583.         if (FAILED(hr))
  3584.             return hr;
  3585.     }
  3586.  
  3587.     return S_OK;
  3588. }
  3589.  
  3590. void
  3591. TrivialData::ComputeNormals()
  3592. {
  3593.     HRESULT hr = S_OK;
  3594.  
  3595.     if ((m_pmcSelectedMesh != NULL) && (m_pmcSelectedMesh->ptmDrawMesh != NULL))
  3596.     {
  3597.         hr = D3DXComputeNormals(m_pmcSelectedMesh->ptmDrawMesh, NULL);
  3598.         GXASSERT(!FAILED(hr));
  3599.  
  3600.         m_pmcSelectedMesh->UpdateViews(m_pdeSelected);
  3601.     }
  3602. }
  3603.  
  3604. void
  3605. TrivialData::ValidateMesh()
  3606. {
  3607.     HRESULT hr = S_OK;
  3608.     LPD3DXMESH pMeshFixed = NULL;
  3609.     LPD3DXBUFFER pbufOutput = NULL;
  3610.     char *pbOutput;
  3611.  
  3612.     if ((m_pmcSelectedMesh != NULL) && (m_pmcSelectedMesh->pMesh != NULL))
  3613.     {
  3614.         hr = D3DXValidMesh(m_pmcSelectedMesh->pMesh, m_pmcSelectedMesh->rgdwAdjacency, &pbufOutput);
  3615.         if (pbufOutput)
  3616.         {
  3617.             ConvertCarriageReturns((char*)pbufOutput->GetBufferPointer(), &pbOutput);
  3618.             pvDialogData = (PVOID)pbOutput;
  3619.  
  3620.             DialogBox(m_hInstance, (LPCTSTR) IDD_INFO, m_hwnd, (DLGPROC) DlgProcOutput);
  3621.  
  3622.             delete []pbOutput;
  3623.  
  3624.             // if failed, then ask if clean mesh should be called
  3625.             if (IDYES == MessageBox(m_hwnd, "The selected mesh failed D3DXValidMesh, do you want to call D3DXCleanMesh?", "Valid Mesh failed", MB_YESNO) )
  3626.             {
  3627.                 GXRELEASE(pbufOutput);
  3628.                 hr = D3DXCleanMesh(D3DXCLEAN_SIMPLIFICATION, m_pmcSelectedMesh->pMesh, m_pmcSelectedMesh->rgdwAdjacency, &pMeshFixed, m_pmcSelectedMesh->rgdwAdjacency, &pbufOutput);
  3629.                 if (pbufOutput)
  3630.                 {
  3631.                     ConvertCarriageReturns((char*)pbufOutput->GetBufferPointer(), &pbOutput);
  3632.                     pvDialogData = (PVOID)pbOutput;
  3633.  
  3634.                     DialogBox(m_hInstance, (LPCTSTR) IDD_INFO, m_hwnd, (DLGPROC) DlgProcOutput);
  3635.  
  3636.                     delete []pbOutput;
  3637.                     GXRELEASE(pbufOutput);
  3638.                 }
  3639.  
  3640.                 if (FAILED(hr))
  3641.                 {
  3642.                     MessageBox(m_hwnd, "Clean mesh failed without errors/warnings - likely due to out of memory", "Clean Mesh failed", MB_OK);
  3643.                 }
  3644.                 else
  3645.                 {
  3646.                     GXRELEASE(m_pmcSelectedMesh->pMesh);
  3647.                     GXRELEASE(m_pmcSelectedMesh->ptmDrawMesh);
  3648.                     m_pmcSelectedMesh->ptmDrawMesh = pMeshFixed;
  3649.                     m_pmcSelectedMesh->pMesh = pMeshFixed;
  3650.                     pMeshFixed->AddRef();
  3651.                     pMeshFixed = NULL;
  3652.                 }
  3653.             }
  3654.         }
  3655.         else if (FAILED(hr))
  3656.         {   
  3657.             MessageBox(m_hwnd, "Valid mesh failed without errors/warnings - likely due to invalid parameters", "Valid Mesh failed!", MB_OK);
  3658.         }
  3659.         else
  3660.         {
  3661.             MessageBox(m_hwnd, "The selected mesh is valid.", "Valid Mesh succeeded!", MB_OK);
  3662.         }
  3663.  
  3664.     }
  3665.  
  3666.     GXRELEASE(pbufOutput);
  3667. }
  3668.